将图像链接转换为 base64 并使用 JSZip 将它们添加到 zip 文件

Conversion image links to base64 and adding them to zip file using JSZip

所以基本上我想在 zip 文件中添加一些图像并能够下载它。我有两个变量保存图像源 - pic1, pic2 和一个全局变量 basePic 用于保存 base64 字符串。我有一个将图像转换为 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 文件中的大部分时间只是第二张图片两次,我必须在调用此函数后 alert 一些东西,因为 basePic 会是空无。我想修复此功能,以便能够轻松地将多个图像源转换为 base64 字符串。

1.How 使此功能正常工作,input_url -> output_base64,多张图片 ?

2.How 无需在每次调用该函数后发出警报即可做到这一点 ?

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

但是,这里也有几点需要考虑:

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

我建议改用以下方法:

  • 在应用开始时(或开始加载文件之前)创建 zip 对象
  • 使用 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>