Dropzone.js + Изменение размера изображения на стороне клиента

Я хочу интегрировать Dropzone.js с изменением размера изображения на стороне клиента. Я знаю, что есть функция изменения размера эскиза, но я бы хотел создать функцию изменения размера основного изображения перед загрузкой. Кто-нибудь может мне помочь, пожалуйста?

Ответ 1

Вот как это сделать, не загружая файл из addedfile.

Важно установить autoQueue параметр false, таким образом dropzone не будет автоматически загружать файлы, выбранные пользователем.

var dropzone = new Dropzone (".dropzone", {
  ...
  autoQueue: false,
  ...
});

Следующим шагом будет изменение размеров и изменение размеров в версии addedfile.

dropzone.on("addedfile", function(origFile) {
  var MAX_WIDTH  = 800;
  var MAX_HEIGHT = 600;

  var reader = new FileReader();

  // Convert file to img

  reader.addEventListener("load", function(event) {

    var origImg = new Image();
    origImg.src = event.target.result;

    origImg.addEventListener("load", function(event) {

      var width  = event.target.width;
      var height = event.target.height;


      // Don't resize if it small enough

      if (width <= MAX_WIDTH && height <= MAX_HEIGHT) {
        dropzone.enqueueFile(origFile);
        return;
      }


      // Calc new dims otherwise

      if (width > height) {
        if (width > MAX_WIDTH) {
          height *= MAX_WIDTH / width;
          width = MAX_WIDTH;
        }
      } else {
        if (height > MAX_HEIGHT) {
          width *= MAX_HEIGHT / height;
          height = MAX_HEIGHT;
        }
      }


      // Resize

      var canvas = document.createElement('canvas');
      canvas.width = width;
      canvas.height = height;

      var ctx = canvas.getContext("2d");
      ctx.drawImage(origImg, 0, 0, width, height);

      var resizedFile = base64ToFile(canvas.toDataURL(), origFile);


      // Replace original with resized

      var origFileIndex = dropzone.files.indexOf(origFile);
      dropzone.files[origFileIndex] = resizedFile;


      // Enqueue added file manually making it available for
      // further processing by dropzone

      dropzone.enqueueFile(resizedFile);
    });
  });

  reader.readAsDataURL(origFile);
});

Здесь используется функция преобразования dataURL в файл dropzone. Процесс может быть проще, если вы используете canvas.toBlob() вместо canvas.toDataURL(), чтобы получить содержимое измененного файла, но последнее не поддерживается всеми браузерами.

Это просто измененная версия этой функции.

function base64ToFile(dataURI, origFile) {
  var byteString, mimestring;

  if(dataURI.split(',')[0].indexOf('base64') !== -1 ) {
    byteString = atob(dataURI.split(',')[1]);
  } else {
    byteString = decodeURI(dataURI.split(',')[1]);
  }

  mimestring = dataURI.split(',')[0].split(':')[1].split(';')[0];

  var content = new Array();
  for (var i = 0; i < byteString.length; i++) {
    content[i] = byteString.charCodeAt(i);
  }

  var newFile = new File(
    [new Uint8Array(content)], origFile.name, {type: mimestring}
  );


  // Copy props set by the dropzone in the original file

  var origProps = [ 
    "upload", "status", "previewElement", "previewTemplate", "accepted" 
  ];

  $.each(origProps, function(i, p) {
    newFile[p] = origFile[p];
  });

  return newFile;
}

Ответ 2

Документация Dropzone о функции изменения размера перед загрузкой сбивает с толку. Как это выглядит, вы можете либо ограничить ширину, ограничить высоту, либо ограничить и то и другое и пожертвовать соотношением сторон, исказив изображение. Это не вариант. Это:

resizeWidth: 1000, resizeHeight: 1000,
resizeMethod: 'contain', resizeQuality: 1.0,

Максимальная ширина или высота не должна превышать 1000 пикселей - в зависимости от того, что больше. Другой будет уменьшен в соответствии с соотношением сторон без искажения изображения. Так, например, в моем тесте я загрузил изображение размером 2688x1512. Dropzone обрезал и изменил размер миниатюры до значения по умолчанию 120x120, но файл, отправленный на сервер, был изменен с помощью Dropzone отдельно, до 1000x562, а затем отправлен на сервер.

Здесь есть интересная оговорка. JPEG файлы будут сжиматься с потерями, поэтому даже изменение размера до 1,0 приведет к потере. Я рассматриваю эту функцию как метод предотвращения чрезмерно больших файлов, но вы должны быть осторожны с изменением размера дважды, если можете избежать этого (один раз на сервере, один раз на клиенте).

Если вам этого недостаточно - и вы действительно хотели перегрузить метод transform - стоит отметить, что следование по пути кода внутри Dropzone немного сбивает с толку, поскольку createThumbnail дорожка createThumbnail используется дважды при каждой загрузке, один раз для создания эскиза, подобного вы ожидаете, и снова предварительно изменить размер изображения здесь, прежде чем передавать его на сервер. Аналогично, метод resize назван смущающе; в то время как resizeWidth и т.д. относятся к подготовке изображения к загрузке, resize относится к изменению размера миниатюры и никак не влияет на изображение, отправляемое на сервер.

Ответ 3

Это можно сделать, минуя загрузку, сделанную Dropzone.js. Для этого вам нужно установить autoQueue: false в параметрах (как в пример загрузки).

Затем вы можете просто отправить миниатюру, или вы можете сделать это сложным способом.


Решение 1: Отправить эскиз

myDropzone.on('thumbnail', function(file, dataURL) {
   $.post('http://example.com', {img: imgToSend})
})

Вы можете определить способ изменения размера/обрезки, добавив функцию изменения размера в параметры.


Решение 2: Изменить размер самостоятельно

Возникла и другая проблема: изображения нужно повернуть (это происходит очень часто). Для этого необходимо использовать тег ориентации EXIF. По-видимому, он теряется при изменении размера, поэтому вам нужно получить эту информацию в интерфейсе, прежде чем изменять размер. Для этого я использовал Exif.js library.

Вот рабочий пример на JSFiddle. Вы можете увидеть URI с измененным размером изображения в консоли.

Ответ 4

Недавно была выпущена версия 5 Dropzone, поэтому, если вы обновитесь до Dropzone 5, вы можете просто использовать resizeWidth и resizeHeigh, чтобы сжать изображение на стороне клиента.

Если вы предоставите только один из них, то dropzone будет учитывать исходное соотношение сторон, например, если вы просто добавите параметр: resizeWidth: 800

Тогда ваше изображение будет сжато до ширины = 800 пикселей, а исходное соотношение сторон изображения будет соблюдаться.

Ответ 5

Хорошо. Мне потребовалось некоторое время, а затем еще немного времени, чтобы найти, как реализовать изменение размера.

Вот окончательное решение, которое работает для меня:

Import css and dropzone.js

<div class="row">
    <div class="col-sm-20 well">
        <form action="@Url.Action("_UploadImages", "Notebooks", new { unique = Model.UniqueId })" 
              method="post" 
              enctype="multipart/form-data"
              class="dropzone"
              id="my-dropzone"></form>
    </div>
</div>

<script type="text/javascript">
    Dropzone.options.myDropzone = {
        url: '@Url.Action("_UploadImages", "Notebooks", new { unique = Model.UniqueId })',
        autoProcessQueue: true,
        uploadMultiple: true,
        parallelUploads: 3,
        maxFilesize: 10,
        resizeWidth: 2048,
        addRemoveLinks: false,
        init: function () {
        }
    }
</script>