jCrop (jQuery) иногда не удается загрузить изображение / область обрезки

#javascript #jquery #jcrop

#javascript #jquery #jcrop

Вопрос:

У меня довольно простая проблема, но я не понимаю, что вызывает проблему. В одном из моих приложений я использую jCrop как небольшое дополнение для обрезки изображений, чтобы они помещались в баннеры / заголовки и т.д. Будут предприняты следующие шаги:

 1) Select an image (using CKFinder for this, CKFinder returns the image path to an input field)
2) Click a button to load the image
3) Crop the image
4) Save the image
  

примерно в 75% случаев все идет по плану, однако в остальных 25% случаев jCrop не удается загрузить область обрезки и оставляет ее пустой. Вот код jQuery, который я использую:

 jQuery('#selectimg').live('click', function(e) { 
  e.preventDefault();
  var newsrc = jQuery('#img2').val();
  jQuery('#cropbox').attr('src', newsrc);
  var jcrop_api = jQuery.Jcrop('#cropbox', {
    boxWidth: 700, 
    boxHeight: 700,
    onSelect: updateCoords,
    onChange: updateCoords
  });
  //Some other JS code come's here for buttons (they work all the time)
});
  

Я заметил, что когда я убрал часть, где #cropbox преобразуется в область обрезки, изображение загружается просто отлично, так что ошибка заключается в var = jcrop_api части, но я постепенно начинаю думать, что для этого нет решения…

Это то, что я пробовал до сих пор:

Создаем div <div id="cropper-box"></div> и используем jQuery('#cropper-box').append('<img src="" id="cropbox" />'); , а затем устанавливаем значение. Я попробовал то же самое, но установил src изображения за 1 шаг, а не после.

Я попытался поместить заполнитель на страницу <img src="placeholder.png" id="cropbox" /> и изменить источник при нажатии кнопки. Это работает, но область обрезки остается размером изображения (300×180 пикселей или что-то в этом роде) и не увеличивается, как следовало бы.

// Редактировать:

Попытка еще немного показала мне, что источник изображения заменяется правильно (! используя Firefox для отображения источника выделенного текста), я дважды проверил URL, но это был правильный URL и рабочее изображение.

В том месте, где должен быть обрезчик, есть белое пятно размером примерно 10×10 пикселей, где появляется значок обрезки (знак плюс) .. но, как было сказано ранее: изображение не отображается.

// Правка 2:

Итак, я взял исходники как для 1-й, так и для 2-й попытки для одного и того же изображения. Как было сказано ранее, при первой попытке изображение не загружается должным образом, а при второй попытке загружается (только если при второй попытке используется то же изображение (!!)).

Выбранный источник страницы показывает 1 отличие, которое заключается в том, что сначала попробуйте:

 <img style="position: absolute; width: 0px; height: 0px;" src="http://95.142.175.17/uploads/files/Desert.jpg">
  

вторая попытка:

 <img style="position: absolute; width: 700px; height: 525px;" src="http://95.142.175.17/uploads/files/Desert.jpg">
  

Я предполагаю, что это изображение, которое заменяется jCrop, но это полная загадка, почему он помещает туда 0 heigth / width в первый раз и правильные размеры во второй раз.

Комментарии:

1. … не уверен, что это изменило бы ситуацию и / или помогло, но я разбил процесс инициализации donw на отдельные этапы: var jcrop_api = null; jcrop_api = $.Jcrop(‘#cropbox’); jcrop_api.setOptions({onChange: [showCoords, setEditDataOK( false ) ], onSelect: showCoords}); jcrop_api. setSelect( [ vx, vy, vx2, vy2 ] ) jcrop_api.фокус();

2. спасибо, но проблему не решил. В случае, если это может быть более распространенной проблемой: при первой попытке для каждого ОТДЕЛЬНОГО изображения происходит сбой. Но если я перезагружу страницу, выберу тот же файл и повторю попытку, это сработает.

3. проблема решена, я сам опубликую ответ на случай, если он кому-нибудь понадобится.

Ответ №1:

Хорошо, ребята, на случай, если кто-нибудь еще столкнется с этой проблемой:

jCrop как бы запутывается, если действия по загрузке изображения и применению jCrop к нему слишком быстро ставятся в очередь друг за другом. Мне все еще кажется странным, что вторая попытка работает идеально, но я думаю, что это как-то связано с размерами кэшированного изображения, которые распознаются DOM страницы или чем-то еще.

Решение, которое я придумал, заключалось в создании функции, которая преобразует #cropbox в область обрезки, а затем устанавливает интервал в 2 секунды, просто чтобы дать jCrop некоторое время для распознавания изображения и его размеров, а затем преобразовать элемент.

Это часть html, которую я использовал (с предварительным загрузчиком):

 <div id="cropper-loading" style="display: none;"><img src="images/analytics/ajax-loader.gif" /></div>
<img id="cropbox" src="images/placeholder.png" style="display: none;" />
  

Как вы можете видеть, изображение cropbox и div, загружающий cropper, скрыты, поскольку они не нужны немедленно. При желании вы могли бы отобразить заполнитель.. Тогда используется эта HTML-форма:

 <input name="image2" id="img2" type="text" readonly="readonly" onclick="openKCFinder(this)" value="click here to select an image" style="width: 285px;" />  <button class="button button-blue" type="submit" name="load" id="selectimg">Load Image in cropper</button>
  

В моем случае я использовал KCFinder для загрузки изображений (это часть CKEditor, на которую действительно стоит обратить внимание!), KCFinder обрабатывает загрузку, переименование и т.д. И после выбора возвращает выбранный путь к изображению (относительный / абсолютный настраивается) в поле ввода.

Затем при нажатии #selectimg вызывается этот код:

 jQuery('#selectimg').click(function(e) { 
    e.preventDefault();
    jQuery('#cropper-loading').css('display', 'block');

    var newsrc = jQuery('#img2').val();

    jQuery('#cropbox').attr('src', newsrc);
    jQuery('#img').val(newsrc);

    function createJcropArea() {
        jQuery('#cropper-loading').css('display', 'none');                                      
        jQuery('#cropbox').css('display', 'block');
        var jcrop_api = jQuery.Jcrop('#cropbox', {
            boxWidth: 700, 
            boxHeight: 700,
            onSelect: updateCoords,
            onChange: updateCoords
        });
        clearInterval(interval);
    }
    var interval = setInterval(createJcropArea, 2000);
});
  

Сначала я запрещаю переход по ссылке, как обычно (или действие кнопки), и после этого отображается загрузочный div (это моя причина для скрытия изображения-заполнителя, иначе это выглядело бы испорченным).

Затем местоположение изображения загружается из поля ввода и копируется в другое (#img), это поле используется для последующей обработки изображения (PHP использует значение #img для загрузки этого изображения). Также одновременно #cropbox src устанавливается на новое изображение.

И вот часть, которая решила мою проблему:

Вместо прямой активации jCrop я создал функцию, которая:

 1) hides the loading icon
2) displays the image
3) converts #cropbox into a jCrop area
4) clean the interval (otherwise it would loop un-ending)
  

И после выполнения этой функции вы можете видеть, что для сохранения я задержался на 2 секунды перед преобразованием области jCrop.

Надеюсь, это поможет кому-нибудь в будущем!

Приветствия и спасибо за то, что подумали @vector и кто бы еще ни сделал 😉

Комментарии:

1. спасибо, это может однажды пригодиться. информация о работе с jCrop иногда может быть немного скудной 🙂

2. Спасибо @pendo. Возникла та же проблема, и ваш ответ направил меня на правильный путь. Я заставил свой работать немного по-другому, но общая идея та же. Вы также можете настроить функцию init для запуска после завершения загрузки изображения с помощью функции jquery .load(). $(«image_cropper»).attr(«src»,YOURSOURCE).load(функция() {do_crop_init_here} ); Вы принудительно загружаете изображение и подключаете функцию для запуска по завершении. Надеюсь, это может помочь людям.

3. Это действительно приятное дополнение!

4. Привет @AlexeyGerasimov, мне нравится ваш подход, поскольку он не требует инструкций по ожиданию. Однако в моем случае это не работает. Она по-прежнему остается пустой… Если я использую функцию перезагрузки браузера, изображение пустое, если я использую запрос propert GET (например, устанавливаю курсор в поле URL и нажимаю ENTER), все работает нормально. У вас есть полный пример кода, где это работает для вас?

5. Ни одно из предложенных решений не сработало для меня. Комментарий здесь, потому что он занимает высокое место в Google. Моя проблема заключалась в том, что ширина и высота изображения изменились с исходного размера изображения на тот, который отображается на странице после загрузки изображения, и jCrop подумал, что размеры изображения были намного меньше фактического размера. Я решил это, чтобы установить видимость css на скрытую, инициализировал jCrop при загрузке изображения и после инициализации jCrop удалил свойство видимости css.

Ответ №2:

Создание объекта ‘Image’ и настройка атрибута ‘src’ не означает, что вы можете обрабатывать изображение так, как будто оно уже было загружено. Кроме того, предоставление любого фиксированного интервала ожидания не гарантирует, что изображение уже загружено.

Вместо этого вам следует настроить обратный вызов ‘onload’ для объекта Image, который затем инициализирует объект Jcrop:

 var src = 'https://example.com/imgs/someimgtocrop.jpg'; 
var tmpImg = new Image();
tmpImg.onload = function() {
   //This is where you can safely create an image and a Jcrop Object
};
tmpImg.src = src; //Note that the 'src' attribute is only added to the Image Object after the 'onload' listener was defined
  

Ответ №3:

Попробуйте библиотеку edge в репозитории здесь: https://github.com/tapmodo/Jcrop

Это должно решить вашу проблему. Строки, которые изменены для решения вашей проблемы:

 // Fix size of crop image.
// Necessary when crop image is within a hidden element when page is loaded.
if ($origimg[0].width != 0 amp;amp; $origimg[0].height != 0) {
  // Obtain dimensions from contained img element.
  $origimg.width($origimg[0].width);
  $origimg.height($origimg[0].height);
} else {
  // Obtain dimensions from temporary image in case the original is not loaded yet (e.g. IE 7.0).
  var tempImage = new Image();
  tempImage.src = $origimg[0].src;
  $origimg.width(tempImage.width);
  $origimg.height(tempImage.height);
}
  

Комментарии:

1. похоже, это не помогает. Поставить предупреждение ($ tempImage. width) или .height() в конце блока else. Вы получите 0. По крайней мере, я делаю. Проблема, похоже, та же, что и раньше, загрузка изображения еще не завершена, поэтому при определении ширины / высоты для него возвращается 0. Дополнительный код в инициализации jcrop не помогает, поскольку требуется задержка между загрузкой изображения и самой инициализацией.

Ответ №4:

Не вызывайте эту функцию onChange : updateCoords

Попробуйте без этого, и он будет работать гладко на мобильных устройствах.

Вы можете создать base64 напрямую и показывать их в виде изображения везде, где захотите.

Ответ №5:

Вот мое странное, но фантастическое решение:

 if (obj.tagName == 'IMG') {
  var tempImage = new Image();
    tempImage.src = $origimg[0].src;
    $origimg.width(tempImage.width);
    $origimg.height(tempImage.height);
  if ($origimg[0].width > 1 amp;amp; $origimg[0].height > 1) {
    $origimg.width($origimg[0].width);
    $origimg.height($origimg[0].height);
  } else {
    var tempImage = new Image();
    tempImage.src = $origimg[0].src;
    $origimg.width(tempImage.width);
    $origimg.height(tempImage.height);
     //console.log('error' $origimg[0].width   $origimg[0].height);
  } 
  

Ответ №6:

Я знаю, что это устарело, но недавно это происходило случайным образом при моей установке. Обнаружено, что это было связано с тем, что изображения загружались не полностью до инициализации jCrop.

Все, что потребовалось для исправления, это обернуть материал инициализации jCrop внутри

$(window).on("load", function () { //jcrop stuff here });

И с тех пор он работает хорошо.