如何使用canvas将多个图像转换为base64

时间:2018-01-29 16:59:46

标签: javascript canvas base64 local-storage data-url

我正在存储base64编码的图像,目前我只能创建一个代码(我试图创建两个代码,但看起来第二个被覆盖)。我没有得到画布绘图的概念,所以我认为这是我试图解决这个问题的根本问题。

当前行为:它将相同的DataUrl存储在本地存储中两次。它会记录正确的信息。 favicon-green正在存储,而不是红色

如何使用画布编码多个base64图像?

HTML:

    <head>
        ...
        <link id="favicon" rel="icon" src="/assets/favicon-red-16x16.ico.png">
    </head>
    <body>
        ...
        <!-- hidden images to store -->
        <img id="favicon-green" rel="icon" src="/assets/favicon-green-16x16.ico.png" width="16" height="16" />
        <img id="favicon-red" rel="icon" src="/assets/favicon-red-16x16.ico.png" width="16" height="16" />
        ...
    </body>

JS:

    // cache images
    function storeImages() {

        // my sorry attempt to create two canvas elements for two image encodings
        var canvasGreen = document.createElement('canvas');
        var canvasRed = document.createElement('canvas');

        // painting both images
        var ctxGreen = canvasGreen.getContext('2d');
        var ctxRed = canvasRed.getContext('2d');

        // getting both images from DOM
        var favGreen = document.getElementById('favicon-green');
        var favRed = document.getElementById('favicon-red');

        // checking if images are already stored
        var base64Green = localStorage.getItem('greenFavicon');
        var base64Red = localStorage.getItem('redFavicon');
        console.log('storing...')

        if (base64Green == null && window.navigator.onLine || base64Red == null && window.navigator.onLine) {
            ctxGreen.drawImage(favGreen, 0, 0);
            ctxRed.drawImage(favRed, 0, 0);

            // getting images (the DataUrl is currently the same for both)
            base64Green = canvasGreen.toDataURL();
            base64Red = canvasRed.toDataURL();
            localStorage.setItem('greenFavicon', base64Green);
            localStorage.setItem('redFavicon', base64Red);
            console.log("are they equal : ", base64Green == base64Red); // returns true
        }
    }
    storeImages();

1 个答案:

答案 0 :(得分:1)

我没有发现您的代码特别错误。如果代码不是直接复制和粘贴的话,我会用细齿来看看它,以确保你不会切换任何红色和绿色。

在将画布转换为数据网址时,不应该有任何令人惊讶的机制。

以下是两个简单的例子:

&#13;
&#13;
const a = document.createElement('canvas');
const b = document.createElement('canvas');

const aCtx = a.getContext('2d');
const bCtx = b.getContext('2d');

aCtx.fillStyle = '#000';
aCtx.fillRect(0, 0, a.width, a.height);

const aUrl = a.toDataURL();
const bUrl = b.toDataURL();

console.log(aUrl == bUrl, aUrl, bUrl);
console.log('First difference index:', Array.prototype.findIndex.call(aUrl, (aChar, index) => aChar !== bUrl[index]));
&#13;
&#13;
&#13;

请注意它们是不同的。但是,请注意它们也开始非常相似,并且你必须在很多方面开始看到差异(在我的例子中,角色70)。我会仔细检查它们实际上是否相同(通过比较它们就像我一样)。它可能只是看起来一样。

你可能会做的另一件事,更多的是代码风格的东西,但也可能有助于意外的绿色和红色混合,是一个函数只保存一个,然后调用它两次。

const saveImage = (imageId, key) => {
    if (localStorage.getItem(key)) {
      return; // already saved
    }

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const image = document.getElementById(imageId);
    ctx.drawImage(image, 0, 0);

    if (window.navigator.onLine) {
      localStorage.setItem(key, canvas.toDataURL());
    }
}

saveImage('favicon-green', 'greenFavicon');
saveImage('favicon-red', 'redFavicon');

这不仅会清理您的代码并保留它DRY,还有助于避免功能中红色和绿色之间的意外混淆。

经过一些评论之后,我意识到另一种可能性是你在图像加载之前尝试将图像绘制到画布上。这将导致它绘制空白图像,但除此之外它表现得很好。

您可以通过控制台记录此功能来快速测试:

console.log(image.width === 0);

设置图像变量后。如果值为true,则图像尚未加载(在加载之前,图像的宽度和高度为0)。在尝试保存之前,您需要确保等到图像加载完毕。

执行此操作的最佳方法是使用addEventListener()

document.getElementById('favicon-green').addEventListener('load', () => {
  saveImage('favicon-green', 'greenFavicon');
});

还有一个问题,因为如果图像以某种方式已经在代码运行的时候加载,它就永远不会触发。您还需要查看图像的宽度。这是一个为您完成所有操作的功能,并返回Promise,以便您知道它已完成:

&#13;
&#13;
const saveImage = (imageId, key) => new Promise(resolve => {
    if (localStorage.getItem(key)) {
      return resolve(); // already saved
    }

    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');
    const image = document.getElementById(imageId);
    
    const onImageLoaded = () => {
      ctx.drawImage(image, 0, 0);
      
      if (window.navigator.onLine) {
        localStorage.setItem(key, canvas.toDataURL());
      }
      
      resolve();
    }
    
    if (image.width > 0) {
      onImageLoaded();
    } else {
      image.addEventListener('load', onImageLoaded);
    }
});

saveImage('favicon-green', 'greenFavicon').then(() => console.log('saved'));
&#13;
&#13;
&#13;