Canvas toDataUrl 增加了图像文件大小

22

使用toDataUrl()将图像标签的源设置为图像时,我发现保存的图像比原始图像要大得多。

在下面的示例中,我没有指定toDataUrl函数的第二个参数,因此默认质量正在使用。这导致生成的图像比原始图像尺寸大得多。当指定1作为完全质量时,生成的图像甚至更大。

有人知道为什么会发生这种情况或者我该如何阻止它吗?

            // create image
            var image = document.createElement('img');

            // set src using remote image location
            image.src = 'test.jpg';

            // wait til it has loaded
            image.onload = function (){

            // set up variables
            var fWidth = image.width;
            var fHeight = image.height;

            // create canvas
            var canvas = document.createElement('canvas');
            canvas.id = 'canvas';
            canvas.width = fWidth;
            canvas.height = fHeight;
            var context = canvas.getContext('2d');

            // draw image to canvas
            context.drawImage(image, 0, 0, fWidth, fHeight, 0, 0, fWidth, fHeight);

            // get data url 
            dataUrl =  canvas.toDataURL('image/jpeg');

            // this image when saved is much larger than the image loaded in
            document.write('<img src="' + dataUrl + '" />');

            }
谢谢 :D
下面是一个例子,不幸的是,图片不能跨域,所以我只能拉一个jsfiddle的图片。 http://jsfiddle.net/ptSUd/ 这张图片大小为7.4kb,如果你保存输出的图片,会发现它大小为10kb。更详细的图片差异更加明显。如果将toDataUrl质量设置为1,则该图片的大小为17kb。
我也在使用Firefox 10,在Chrome中使用时,图像尺寸仍然较大,但差别没有那么大。

3
数据URL以base64编码存储(增加1/3的大小)。在浏览器中存储算法可能不如原始使用方式优化。 - kirilloid
这仅适用于远程存储的图像,使用文件输入加载的图像大小正确。 - Lishamatish
它们是一样的吗?真实网站上的远程图像可能会更好地优化。 - kirilloid
我可以确定,我使用的远程图像示例大小为59kb。在从上面生成的图像标签重新保存后,该图像的大小被称为134kb。将这个59kb的图像保存到我的硬盘上,然后上传结果是一个59kb的图像。由于某种原因,当图像是远程的时候,它会使生成的图像变得更大。 - Lishamatish
1
非常好的问题,因为有很多文章展示了如何在上传到服务器之前在客户端上“缩小”图像。然而,我读过的所有文章都没有提到数据膨胀问题。只有在浪费数小时后才会意识到canvas不是一个很好的图像调整大小解决方案。+1 - Yogi
3个回答

13

toDataURL()方法返回的字符串并不代表原始数据。

我刚刚进行了一些广泛的测试,结果显示创建的数据URL取决于浏览器(而不是操作系统)。

 Environment             -    md5 sum                       - file size
    Original file        - c9eaf8f2aeb1b383ff2f1c68c0ae1085 - 4776 bytes
WinXP Chrome 17.0.963.79 - 94913afdaba3421da6ddad642132354a - 7702 bytes
Linux Chrome 17.0.963.79 - 94913afdaba3421da6ddad642132354a - 7702 bytes
Linux Firefox 10.0.2     - 4f184006e00a44f6f2dae7ba3982895e - 3909 bytes

获取 data-URI 的方法并不重要,以下代码片段用于验证文件上传的 data-URI 也是不同的:

测试案例:http://jsfiddle.net/Fkykx/

<input type="file" id="file"><script>
document.getElementById('file').onchange=function() {
    var filereader = new FileReader();
    filereader.onload = function(event) {
        var img = new Image();
        img.onload = function() {
            var c = document.createElement('canvas'); // Create canvas
            c.width = img.width;
            c.height = img.height;  c.getContext('2d').drawImage(img,0,0,img.width,img.height);
            var toAppend = new Image;
            toAppend.title = 'Imported via upload, drawn in a canvas';
            toAppend.src = c.toDataURL('image/png');
            document.body.appendChild(toAppend);
        }
        img.src = event.target.result; // Set src from upload, original byte sequence
        img.title = 'Imported via file upload';
        document.body.appendChild(img);
    };
    filereader.readAsDataURL(this.files[0]);
}
</script>

非常有帮助的答案。感谢您确认编码行为是一致的且与浏览器相关。 - Joe Coder
需要注意的一点是,至少Chrome v56生成的非渐进式JPEG比渐进式JPEG略大(特别是在质量为0..10和90..100时)。 - piotr_cz

5

图片的大小主要由浏览器内置编码器的质量决定,与原始图像的大小关系甚小。一旦将任何东西绘制到canvas上,你只能得到像素,无法再得到原始图像。 toDataURL不能神奇地重新构建被绘制到canvas上的图像。 如果您想要一个与原始图像大小相同的文件,请使用原始图像。


3
看起来kirilloid和Rob解决了这个问题。我也遇到了这个问题,它似乎是一个组合问题:
- dataURL使用base64编码,使其大约增加了1.37倍 - 每个浏览器对toDataURL函数的处理方式不同 base64编码图像大小 我在win8.1上的Firefox和Chrome中测试了我的缩略图生成器,并得到了以下数据URL字符串大小:
- Firefox = 3.72kB - Chrome = 3.24kB
当我的原始图像转换为dataURL时,从32kB增加到了45kB。
我认为base64部分是较大的因素,所以我现在的计划是在将其存储在服务器上之前将dataURL转换回二进制字节数组(可能在客户端上,因为我的服务器很懒)。

我现在的计划是将DataURL转换回二进制字节数组,这将给你比原始图像字节数据更大的字节数据... - Rajshekar Reddy

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接