【问题标题】:How to convert multiple images to base64 with canvas如何使用画布将多个图像转换为base64
【发布时间】:2018-01-29 16:59:45
【问题描述】:

我正在存储 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();

【问题讨论】:

  • 它有什么作用?它会打印您的控制台日志吗?你做了什么调试?它是否包含在您的 if 语句中?它会引发任何控制台错误吗?
  • 没有错误,它将相同的DataUrl存储在本地存储中两次。它确实记录了正确的信息。 favicon-green 正在被存储,而不是红色(更新的问题)

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


【解决方案1】:

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

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

这是两个的简单示例:

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]));

请注意它们是不同的。但是,请注意,它们开始时也非常相似,并且您必须走很长一段路才能开始看到差异(在我的示例中,字符 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,还有助于避免函数中的红色和绿色意外混淆。


经过一些 cmet 来回后,我意识到另一种可能性是您试图在图像加载之前将图像绘制到画布上。这将导致它绘制空白图像,但在其他方面表现得很好。

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

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

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

最好的方法是使用addEventListener()

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

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

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'));

【讨论】:

  • 嗯。所以我尝试了你建议的 DRY 方法,我直接复制了它,然后我运行了 '''console.log('is equal : ', localStorage.getItem('redFavicon') == localStorage.getItem('greenFavicon')); ''' 并得到了真实的。我不确定发生了什么,在测试之前我已经清除了缓存
  • 嗯,这很奇怪。尝试使用document.body.append(canvas) 将画布添加到浏览器中,这样您就可以实际看到画布并确保它正确绘制。也许它不是绘图,只是保存 2 个空白画布或其他东西。此外,请仔细检查任何控制台和网络错误。
  • 好吧,它们肯定是不同的,它附加了我的两个图标(一个红点和一个绿点),但它仍然说 URI 是相等的......
  • 这很好奇。当您检查它们的值时,同时输出两者并查看它们。我想知道当它们被检索时,它们是否由于某种原因为空(这意味着它们是相同的)。
  • 所以他们肯定有一个URI,他们是一样的,当我点击它创建的链接时,两个画布都是空白的。
猜你喜欢
  • 2018-06-26
  • 1970-01-01
  • 2016-04-30
  • 1970-01-01
  • 2016-09-04
  • 1970-01-01
  • 2015-02-20
  • 2017-09-08
  • 1970-01-01
相关资源
最近更新 更多