【问题标题】:Conversion image links to base64 and adding them to zip file using JSZip将图像链接转换为 base64 并使用 JSZip 将它们添加到 zip 文件
【发布时间】:2016-11-07 13:34:57
【问题描述】:

所以基本上我想在 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 文件中只有第二张图片两次,调用此函数后我必须 alert 一些东西,因为如果没有 basePic 将是空的。我想修复此功能,以便能够轻松地将多个图像源转换为 base64 字符串。

1.如何让这个函数正常工作,input_url -> output_base64,有多个图像?

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

【问题讨论】:

    标签: javascript image canvas base64 jszip


    【解决方案1】:

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

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

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

    我会建议以下方法:

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

    【讨论】:

    • 在我的示例中,主要问题是将图像转换为 base64 的函数,甚至在添加到 zip 之前。我有点希望修复该功能,但我会尝试您的解决方案,看看它是否会起作用。
    • Thx,工作正常,即使使用 AJAX 和更多图像,但我仍然必须在保存文件之前进行一次“alert()”调用,以便获得适当数量的要压缩的对象。我想这是异步的问题。这是一项重大改进,但有什么想法可以模拟“alert()”,让编译器在尝试制作 zip 文件之前等待所有对象??
    • @markE 很抱歉让您失望了,但是不,这与 不同 的事情有关(如当时所述)。 :)
    猜你喜欢
    • 2015-03-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-02-19
    • 1970-01-01
    • 1970-01-01
    • 2012-02-10
    相关资源
    最近更新 更多