javascript - 我应该使用哪个功能? .toDataURL() 还是 .toBlob()?

标签 javascript canvas html5-canvas

我想使用 JavaScript 在客户端调整图像大小。我找到了两种解决方案,一种是使用 .toDataURL() 函数,另一种是使用 .toBlob() 函数。两种解决方案都有效。好吧,我只是好奇这两个功能有什么区别?哪一个更好?或者什么时候应该使用 .toDataURL() 函数或 .toBlob() 函数?

这是我用来输出这两个函数的代码,并且图像大小(字节)和图像颜色略有不同(我不确定这个)。代码有问题吗?

<html>
    <head>
        <title>Php code compress the image</title>
    </head>
    <body>
        <input id="file" type="file" onchange="fileInfo();"><br>
        <div>
            <h3>Original Image</h3>
            <img id="source_image"/>
            <button onclick="resizeImage()">Resize Image</button>
            <button onclick="compressImage()">Compress Image</button>
            <h1 id="source_image_size"></h1>
        </div>
        <div>
            <h3>Resized Image</h3>
            <h1> image from dataURL function </h1>
            <img id="result_resize_image_dataURL"/>

            <h1> image from toBlob function </h1>
            <img id="result_resize_image_toBlob"/>
        </div>
        <div>
            <fieldset>
                <legend>Console output</legend>
                <div id='console_out'></div>
            </fieldset>
        </div>

        <script>
            //Console logging (html)
            if (!window.console)
            console = {};

            var console_out = document.getElementById('console_out');
            var output_format = "jpg";

            console.log = function(message) {
                console_out.innerHTML += message + '<br />';
                console_out.scrollTop = console_out.scrollHeight;
            }

            var encodeButton = document.getElementById('jpeg_encode_button');
            var encodeQuality = document.getElementById('jpeg_encode_quality');

            function fileInfo(){
                var preview = document.getElementById('source_image');
                var file   = document.querySelector('input[type=file]').files[0];
                var reader  = new FileReader();
                reader.addEventListener("load", function(e) {
                    preview.src = e.target.result;
                }, false);
                if (file) {
                    reader.readAsDataURL(file);
                }
            }
            function resizeImage() {
                var loadedData = document.getElementById('source_image');
                var result_image = document.getElementById('result_resize_image_dataURL');

                var cvs = document.createElement('canvas'),ctx;
                cvs.width = Math.round(loadedData.width/4);
                cvs.height = Math.round(loadedData.height/4);
                var ctx = cvs.getContext("2d").drawImage(loadedData, 0, 0, cvs.width, cvs.height);
                cvs.toBlob(function(blob) {
                    var newImg = document.getElementById('result_resize_image_toBlob'),
                        url = URL.createObjectURL(blob);
                    newImg.onload = function() {
                        // no longer need to read the blob so it's revoked
                        URL.revokeObjectURL(url);
                    };

                    newImg.src = url;
                    console.log(blob.size/1024);
                }, 'image/jpeg', 0.92);

                var newImageData = cvs.toDataURL('image/jpeg', 0.92);
                var result_image_obj = new Image();
                result_image_obj.src = newImageData;
                result_image.src = result_image_obj.src;
                var head = 'data:image/png;base64,';
                var imgFileSize = ((newImageData.length - head.length)*3/4)/1024;
                console.log(imgFileSize);
            }

已编辑:

基于Result of html5 Canvas getImageData or toDataURL - Which takes up more memory? ,据说是这样

"DataURL (BASE64) is imageData compressed to JPG or PNG, then converted to string, and this string is larger by 37% (info) than BLOB."

这个字符串是什么意思?它与以字节为单位的大小相同吗?使用我上面提供的代码,大小差异小于 1Kb(小于 1%)。 .toBlob() 总是比 .toDataURL() 函数更好吗?或者在特定条件下最好使用 .toDataURL() 函数?

最佳答案

一定要选择toBlob() .
toDataURL实际上只是规范中的一个早期错误,如果几个月后定义它,它肯定不会再出现了,因为我们可以使用 toBlob 做同样的事情,但效果更好。 .

toDataURL()是同步的,并且在执行不同操作时会阻塞您的 UI

  • 将位图从 GPU 移至 CPU
  • 转换为图像格式
  • 转换为 Base64 字符串

toBlob()另一方面,只会同步执行第一个项目符号,但会以非阻塞方式转换为图像格式。而且,它根本不会执行第三个项目。
所以在原始操作中,这意味着 toBlob()以更好的方式做更少的事情。

toDataURL结果占用的内存比 toBlob 更多的。

toDataURL 返回的数据 URL是 USVString ,其中包含以 base64 压缩的完整二进制数据。
正如您问题中的引述所述,base64 编码本身意味着二进制数据现在将增大约 37%。但这里它不仅编码为base64,还使用UTF-16编码存储,这意味着每个ascii字符将占用原始ascii文本所需内存的两倍,并且我们跳转到比原始二进制数据大174%的文件。 ..
一切还没有结束...每次你在某个地方使用这个字符串时,例如 src DOM 元素*,或者通过网络请求发送它时,该字符串可以再次在内存中重新分配。
*尽管现代浏览器似乎有处理这种情况的机制

(几乎)永远不需要数据url。

使用 data-url 可以做的所有事情,使用 Blob 和 Blob-URI 都可以做得更好。

要显示或本地链接到二进制数据(例如,供用户下载),请使用 Blob-URI,使用 URL.createObjectURL()方法。
它只是一个指向 Blob 本身所指向的内存中保存的二进制数据的指针。这意味着您可以根据需要多次复制 blob-URI,它始终是一个约 100 个字符的 UTF-16 字符串,并且二进制数据不会移动。

如果您希望将二进制数据发送到服务器,send it as binary directly ,或通过 multipart/formdata request .

如果您希望将其保存在本地,请使用IndexedDB ,它能够保存二进制文件。在 LocalStorage 中存储二进制文件是一个非常糟糕的主意,因为必须在每次页面加载时加载 Storage 对象。

您可能需要 data-urls 的唯一情况是,如果您希望创建需要嵌入二进制数据的独立文档,以便在当前文档失效后可以访问。但即便如此,要从 Canvas 创建图像的 data-url 版本,请使用 FileReader您将 canvas.toBlob() 返回的 Blob 传递给它。这将实现完全的异步转换,避免您的 UI 无缘无故被阻止。

关于javascript - 我应该使用哪个功能? .toDataURL() 还是 .toBlob()?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/59020799/

相关文章:

javascript - 单击图标打开 HTML5 日期选择器

javascript - underscore.js 库中的每个实现

javascript - 有没有办法从网络摄像头捕捉图像?

android - 全息进度条发光效果

android - 如何在其中添加带有textview的彩色矩形

javascript - fabric js Canvas 初始化错误

javascript - 为什么 Javascript 中的类变量在尝试多次调用它们或将它们分配给局部变量时会消失?

javascript - Sinon.JS 错误 URL 无效,如何解决

javascript - 喝着 Jasmine 来运行我自己的类(class)

javascript - 24 次迭代 javascript 循环仅显示 10 个 Canvas