3

所以基本上我想在 zip 文件中添加一些图像并能够下载它。我有两个保存图像来源的变量——pic1 pic2 和一个用于保存 base64 字符串的全局变量basePic 。我有一个将图像转换为 base64 的功能:

var pic; //http://www.somesite.com/i/picture.jpg
var pic2; //http://www.somesite.com/i/picture2.jpg
var basePic;// base64 string of an image

function getBase64FromImageUrl(url) {
    var img = new Image();
    img.setAttribute('crossOrigin', 'anonymous');

    img.onload = function () {
    var canvas = document.createElement("canvas");
    canvas.width =this.width;
    canvas.height =this.height;

    var ctx = canvas.getContext("2d");
    ctx.drawImage(this, 0, 0);

    var dataURL = canvas.toDataURL("image/png");
    basePic=dataURL.replace(/^data:image\/(png|jpg);base64,/, "");  
    }; 

    img.src = url; // I was trying to put this after setAttribute, but it's the same effect
    }

后来我试图创建一个 zip 文件并像这样调用这个函数:

var zip = new JSZip();

getBase64FromImageUrl(pic);
alert("random text"); // without it, it's just empty file added to zip
zip.file("picture.png",basePic, {base64: true});

getBase64FromImageUrl(pic2);
alert("random text");
zip.file("picture2.png",basePic, {base64: true});

zip.generateAsync({type:"blob"})
.then(function(content) {
saveAs(content, "example.zip");
});

此功能适用于一张图片,但多张图片会变得更加随机。如果我在不刷新页面的情况下运行我的代码几次,它可能会得到我需要的结果。但大多数情况下,我的 zip 文件中只有第二张图片两次,调用此函数后我必须提醒一些东西,因为没有basePic将是空的。我想修复此功能,以便能够轻松地将多个图像源转换为 base64 字符串。

1.如何使这个功能正常工作,input_url -> output_base64,有多个图像?

2.如何做到这一点,而无需在每次调用该函数后发出警报?

4

1 回答 1

6

问题是压缩过程在图像加载之前开始。将文件添加到 zip 存档的过程必须从onload处理程序内部开始。

但是,这里也有几件事情需要考虑:

  • 如果您想将图像按原样添加到存档中,则无需通过画布
  • 与 Data-URI 之间的转换非常昂贵且内存成本很高。JSZip 在内部使用 pako_delate,它在类型化数组视图中效果更好(Uint8Array

我会提出以下方法:

  • 在应用程序开始时(或开始加载文件之前)创建 zip 对象
  • 使用 s 加载每个文件XMLHttpRequest并将内容请求为ArrayBuffer. 这将允许您将任何类型的文件直接加载为二进制格式,从而提高性能和资源。
  • 随文件添加
  • 当所有 URL 都被传递时,调用该generateAsync()方法,你应该完成了。

例子

这不是一个可用于生产的示例,也不打算这样做,但它将显示主要步骤。根据您的情况进行调整,在适当的情况下添加错误处理和健全性检查。

// create archive before loading process begin
var zip = new JSZip();

// image list to add:
var images = [
      "//i.imgur.com/qDFCWVnb.jpg",
      "//i.imgur.com/VBvzEq1b.jpg",
      "//i.imgur.com/ZWtUEuLb.jpg"
    ],
    index = 0;  // for loader

// function to load a single image as arraybuffer using XMLHttpRequests
// it will assume cross-origin usage is allowed
function loadAsArrayBuffer(url, callback) {
  var xhr = new XMLHttpRequest();
  xhr.open("GET", url);
  xhr.responseType = "arraybuffer";
  xhr.onerror = function() {/* handle errors*/};
  xhr.onload = function() {
    if (xhr.status === 200) {callback(xhr.response, url)}
    else {/* handle errors*/}
  };
  xhr.send();
}

// loading process. Here it will load one and one image.
// You can modify it to load several at once but some browsers put
// a cap on how many XHR connections can be open at the same time..
(function load() {
  if (index < images.length) {
    loadAsArrayBuffer(images[index++], function(buffer, url) {
      var filename = getFilename(url);
      zip.file(filename, buffer); // image has loaded, add it to archive
      load();                     // load next image
    })
  }
  else {                          // done! present archive somehow
    zip.generateAsync({type:"blob"}).then(function(content) {
      // save out
      lnk.href = (URL || webkitURL).createObjectURL(content);
      lnk.innerHTML = "Right-click + Save as to download zip file";
      lnk.download = "DemoZip.zip";
    });
  }
})();

// Just for this demo! keep separate array with filename or
// modify to allow for "filename-less" uris.
function getFilename(url) {
  return url.substr(url.lastIndexOf("/") + 1)
}
<script src="https://raw.githubusercontent.com/Stuk/jszip/master/dist/jszip.min.js"></script>
Loading external lib + images... hold on...
<br><a id=lnk></a>

于 2016-07-05T18:46:53.377 回答