在不使用画布的情况下在 JavaScript 中调整 Base-64 图像的大小

IT技术 javascript canvas resize html5-canvas base64
2021-02-12 22:44:37

我需要一种无需使用 HTML 元素即可在 JavaScript 中调整图片大小的方法。

我的移动 HTML 应用程序捕获照片,然后将它们转换为 base64 字符串。此后,我需要在将它们发送到 API 之前调整它们的大小以节省存储空间。

我正在寻找一种与使用画布元素不同且更合适的调整大小的方法,有没有办法?

6个回答

避免主要 HTML 受到影响的一种方法是创建一个远离 DOM 树的屏幕外画布。

这将提供位图缓冲区和本机编译代码来编码图像数据。直接做:

function imageToDataUri(img, width, height) {

    // create an off-screen canvas
    var canvas = document.createElement('canvas'),
        ctx = canvas.getContext('2d');

    // set its dimension to target size
    canvas.width = width;
    canvas.height = height;

    // draw source image into the off-screen canvas:
    ctx.drawImage(img, 0, 0, width, height);

    // encode image to data-uri with base64 version of compressed image
    return canvas.toDataURL();
}

如果要生成与 PNG(默认)不同的格式,只需指定如下类型:

return canvas.toDataURL('image/jpeg', quality);  // quality = [0.0, 1.0]

值得注意的是,CORS限制适用于toDataURL().

如果您的应用程序仅提供 base64 编码图像(我假设它们是带有 base64 数据的 data-uri?),那么您需要先“加载”图像:

var img = new Image;

img.onload = resizeImage;
img.src = originalDataUriHere;

function resizeImage() {
    var newDataUri = imageToDataUri(this, targetWidth, targetHeight);
    // continue from here...
}

如果源是纯 base-64 字符串,只需向其添加一个标头即可使其成为数据 uri:

function base64ToDataUri(base64) {
    return 'data:image/png;base64,' + base64;
}

只需将image/png部分替换为base64 字符串表示的类型(即使其成为可选参数)。

谢谢肯,我会试试这个!
2021-03-19 22:44:37
对我不起作用。它创建了一个 base64 字符串,但它只是透明的。
2021-03-23 22:44:37
@Brettetete 如果绘制了任何图像,则它们需要满足 CORS 要求。
2021-03-25 22:44:37
什么是imageToDataUri
2021-04-01 22:44:37
@boop 你必须等到 img 加载完毕。使用 onload 事件
2021-04-06 22:44:37

肯的​​答案是正确的答案,但他的代码不起作用。我对其进行了一些调整,现在它可以完美运行。要调整数据 URI 的大小:

// Takes a data URI and returns the Data URI corresponding to the resized image at the wanted size.
function resizedataURL(datas, wantedWidth, wantedHeight)
    {
        // We create an image to receive the Data URI
        var img = document.createElement('img');

        // When the event "onload" is triggered we can resize the image.
        img.onload = function()
            {        
                // We create a canvas and get its context.
                var canvas = document.createElement('canvas');
                var ctx = canvas.getContext('2d');

                // We set the dimensions at the wanted size.
                canvas.width = wantedWidth;
                canvas.height = wantedHeight;

                // We resize the image with the canvas method drawImage();
                ctx.drawImage(this, 0, 0, wantedWidth, wantedHeight);

                var dataURI = canvas.toDataURL();

                /////////////////////////////////////////
                // Use and treat your Data URI here !! //
                /////////////////////////////////////////
            };

        // We put the Data URI in the image's src attribute
        img.src = datas;
    }
// Use it like that : resizedataURL('yourDataURIHere', 50, 50);
您没有在任何地方使用“数据”。
2021-03-26 22:44:37
我看不懂代码,我应该在“在此处使用和处理您的数据 URI”中输入什么内容?
2021-03-28 22:44:37
您的代码运行良好,可以轻松显示。通过:var newImage = document.createElement('img'); newImage.src = dataURI; document.getElementById("imgTest").innerHTML = newImage.outerHTML; 这使山雀显示到浏览器
2021-04-05 22:44:37
“img.src = 数据;” 在代码段的底部。
2021-04-12 22:44:37

Pierrick Martellière 是最好的答案,我只是想指出您应该使用异步函数来实现它。之后,您将能够执行以下操作:

var newDataUri = await resizedataURL(datas,600,600);

这将在进入下一步之前等待函数的结果。这是一种更简洁的代码编写方式。这是 Pierrick 的函数,稍作修改:

// Takes a data URI and returns the Data URI corresponding to the resized image at the wanted size.
function resizedataURL(datas, wantedWidth, wantedHeight){
    return new Promise(async function(resolve,reject){

        // We create an image to receive the Data URI
        var img = document.createElement('img');

        // When the event "onload" is triggered we can resize the image.
        img.onload = function()
        {        
            // We create a canvas and get its context.
            var canvas = document.createElement('canvas');
            var ctx = canvas.getContext('2d');

            // We set the dimensions at the wanted size.
            canvas.width = wantedWidth;
            canvas.height = wantedHeight;

            // We resize the image with the canvas method drawImage();
            ctx.drawImage(this, 0, 0, wantedWidth, wantedHeight);

            var dataURI = canvas.toDataURL();

            // This is the return of the Promise
            resolve(dataURI);
        };

        // We put the Data URI in the image's src attribute
        img.src = datas;

    })
}// Use it like : var newDataURI = await resizedataURL('yourDataURIHere', 50, 50);

有关更多详细信息,您可以查看 MDN 文档:https : //developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Promise

这个问题特别提到“没有画布”。这不是一个答案。投反对票。
2021-03-15 22:44:37
@AdamBarnes 技术问题的一个好的答案并不总是试图结合提问者的先入为主的观念。OP 说他们不想要画布元素,但没有说明原因。一个人可能会假设他们是在错误的观念下操作的,即您必须将画布元素添加到 DOM,但事实并非如此。糟糕的投票,这是一个不错的解决方案,即使它没有严格涵盖 OP 的未指定限制。不喜欢硬编码方面。它可能不包括 OP 的情况,但对于那些可以使用 canvas 元素并认为必须避免它的人来说,它仍然是一个很好的解决方案。
2021-03-18 22:44:37
此解决方案不考虑使用移动相机上传的图像,并且可能存在方向问题,例如图像可能会旋转。
2021-03-23 22:44:37
@AdamBarnes 我希望你对所有其他答案投反对票 ;) 如果你阅读了问题的前 2 或 3 条评论,你实际上可以读到目标是不在 DOM 上插入任何元素并在后面(后端)执行。干杯小伙子!
2021-04-01 22:44:37
@pavloko 我编写了一个图像上传实用程序,它确实从图像中解析了方向标签,旋转了它,并设置了一个新的方向标签。然后谷歌浏览器更新开始尊重方向标签。这可能不值得付出努力,因为那是最后添加对方向支持的流行浏览器之一。我们最终不得不将其剥离,因为与浏览器会做的事情作斗争是不值得的。我认为唯一的时间方向是至关重要的,它是在后端由不尊重或支持方向的库操作的。
2021-04-12 22:44:37

是的你可以。这些解决方案不仅适用于将图像转换为 base64,还适用于调整大小。

  1. 您可以通过jpg-js将 js 文件转换为图像位图。并且您只能通过此库调整大小,但是在从非常大的图像调整到非常小的情况下,质量会很差。高分辨率图像的最佳方法是通过 jpg-js 将文件转换为位图,然后通过 Pica lib 调整此位图的大小。
  2. 您可以通过 jpg-js 从文件中获取图像数据(或在画布上绘制图像),然后通过调整 lib pica 的大小来调整 canvasImageData 的大小(适用于高分辨率图像,没有画布尺寸限制)
  3. 您可以使用屏幕外画布,无需将画布附加到主体,并调整图像大小。此解决方案会更快,但对于高分辨率图像(例如 6000x6000 像素)来说将是更差的解决方案。在这种情况下,结果画布可能质量不佳或只是空的,或者浏览器可能会出现内存限制异常。(适用于普通和小图像)

Jpg-js 和 Pica 根本不会使用 dom 元素。这些库仅适用于图像数据,没有 dom 元素(画布和图像)。

关于画布,尺寸限制见这篇文章

谢谢你真的回答了这个问题。我不知道为什么人们投票支持依赖于画布的答案,尽管要求避免它成为问题的关键部分......这似乎是 node.js 的唯一解决方案。
2021-03-27 22:44:37

您可以使用原始 Base64 图像处理,如下所示。

看起来很难(仅适用于 png)以及为什么许多人选择使用画布

http://blog.calyptus.eu/seb/2009/05/png-parser-in-javascript/