Dropzone.js + 客户端图片调整大小

19

我想将 Dropzone.js 与客户端图像调整集成。我知道有一个函数可以调整缩略图的大小,但我想创建一个函数,在上传之前调整主图像的大小。请问有人能帮助我吗?


2
我还想知道是否有一个示例展示如何在dropzone中使用"Resize"函数。文档中指出:"resize是用于创建调整大小信息的函数。它以文件作为第一个参数,并且必须返回一个包含srcX、srcY、srcWidth和srcHeight以及trg*的对象。这些值将被ctx.drawImage()使用。"很想看到一个示例。 - BenjiFB
@Satindersingh 在这篇文章中,作者是在上传后调整图像大小,而不是在客户端进行操作...无论如何,感谢提供链接。 - Bruno Rodrigues
5个回答

16

以下是如何在不从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's 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;
}

谢谢!只需要添加允许数据图像<meta http-equiv="Content-Security-Policy" content="default-src 'self'; img-src 'self' data: fbcdn-profile-a.akamaihd.net *.twimg.com *.googleusercontent.com *.xingassets.com vk.com *.yimg.com secure.gravatar.com; style-src 'self' 'unsafe-inline' cdnjs.cloudflare.com maxcdn.bootstrapcdn.com cdn.jsdelivr.net fonts.googleapis.com; font-src 'self' fonts.gstatic.com fonts.googleapis.com cdnjs.cloudflare.com; script-src 'self' clef.io; connect-src 'self' twitter.com *.xing.com; frame-src clef.io">并注意结果类型为PNG。 - ozma
2
更好的压缩可以通过以下方式使用“jpeg”来实现(修改一行):var resizedFile = base64ToFile(canvas.toDataURL("image/jpeg"), origFile); - ozma
这在我的桌面和安卓Chrome浏览器上运行得非常好。然而,在iOS Safari上它不起作用。有人能否建议为什么或者我可以做些什么来让它工作? - comphelp
2
我一直在解决这个问题,导致Safari在iOS上出现问题的行是:var newFile = new File( [new Uint8Array(content)], origFile.name, {type: mimestring} );可能与iOS的严格权限或缺乏从Web浏览器访问文件系统有关。 - comphelp
只需将 new File() 替换为 new Blob(),并相应地放置参数,在 Safari 上对我有效。 - codeomnitrix
显示剩余3条评论

15

Dropzone关于预上传调整大小功能的文档很令人困惑。它的阅读方式似乎是,您可以限制宽度、限制高度或两者兼而有之,并牺牲纵横比,从而扭曲图像。但事实并非如此。以下是正确的:

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

限制宽度或高度最大为1000px - 以较大者为准。另一个将根据长宽比例缩小,而不会扭曲图像。例如,在我的测试中,我上传了一张2688x1512的图片。Dropzone将缩略图裁剪并调整大小为默认的120x120,但是Dropzone单独调整了文件大小为1000x562,然后发送到服务器。

这里有一个有趣的警告。JPEG将被重新压缩,且会有损失,因此即使resizeQuality为1.0,也会导致损失。我认为这个功能是防止文件过大的一种方法,但如果可以避免,您应该小心不要重复调整大小(在服务器和客户端上各一次)。

如果这还不够用 - 而你真的想要超载transform方法 - 值得注意的是,跟随Dropzone内部代码路径有点混乱,因为createThumbnail代码路径每次上传都会使用两次,一次创建缩略图,一次在此之前对图像进行预缩放,然后将其传递给服务器。同样,resize方法的命名令人困惑;虽然resizeWidth等指的是为上传准备图像,但resize指的是为缩略图调整大小,并不影响发送到服务器的图像。


我上传了两个文件,一个宽度大于高度,另一个则相反。然而,使用这段代码后,两个文件都被转换为相同的方向。 - luke_mclachlan

9

最近发布了Dropzone 5版本,如果您升级到Dropzone 5,则可以在客户端使用resizeWidthresizeHeigh来压缩图像。

如果您只提供其中一个参数,那么Dropzone将会保持原始纵横比例。例如,如果您只添加选项:resizeWidth: 800,则您的图像将被压缩为width=800像素,并且您原始图像的纵横比例将得到保留。


1
你知道如何只调整比指定宽度大的图像尺寸吗?例如:如果宽度> 1000px,则调整宽度为800,否则不调整 - little_coder
1
我认为你应该能够覆盖默认的 transformFile 实现,并实现自己的自定义转换逻辑。根据文档transformFile: 默认实现使用 resizeWidth 和 resizeHeight(如果提供)并根据这些尺寸调整图像大小。...查看源代码,它可能会帮助你实现自己的自定义实现。 - Hooman Bahreini

4
可以通过绕过Dropzone.js上传来实现。为此,您必须在选项中设置autoQueue: false(如Bootstrap示例中所示)。
然后您可以只发送缩略图,或者您可以采用困难的方法。

解决方案1:发送缩略图

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

您可以通过在选项中添加“resize”函数来定义调整大小/裁剪的方式。


解决方案2:自己调整大小

还有另一个问题:图像可能需要旋转(这经常发生)。为此,必须使用EXIF方向标记。当您调整大小时,该标记似乎会丢失,因此您必须在前端获取此信息,然后再调整大小。为此,我使用了Exif.js库

这里是JSFiddle上的工作示例。您可以在控制台中查看调整大小后的图像数据URI。


2

好的,花了我一些时间才找到如何实现调整大小。

这是最终的解决方案,适用于我:

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>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接