Javascript - 如何将图像缩小到特定文件大小?

新手上路,请多包涵

在将它们上传到服务器之前,我在 Base64 中对我的图像进行编码。我需要将他们的文件大小缩小到特定大小 (500kB)。我试图获得原始文件大小和所需文件大小之间的比率,并相应地减少高度和宽度。但它不起作用。有什么帮助吗?

原文由 Rafael Reis 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 333
1 个回答

我和你有同样的问题,我需要在将图像上传到我的服务器之前调整图像大小。所以我首先想到的是计算像素数来确定字节数。但很快我注意到大多数图像格式都使用压缩。例如,只有白色像素的 1000x1000 图片将只是普通图像尺寸的一小部分。所以这就是为什么我认为很难将任何维度预先计算为字节数。所以我使用二进制搜索算法来尝试找到应该用于减少宽度和高度的百分比。该图像将多次调整大小以找到完美的百分比,因此效率不高,但我想不出任何其他方法。

 // maxDeviation is the difference that is allowed default: 50kb
// Example: targetFileSizeKb = 500 then result will be between 450kb and 500kb
// increase the deviation to reduce the amount of iterations.
async function resizeImage(dataUrl, targetFileSizeKb, maxDeviation = 50) {
    let originalFile = await urltoFile(dataUrl, 'test.png', 'image/png');
    if (originalFile.size / 1000 < targetFileSizeKb)
        return dataUrl; // File is already smaller

    let low = 0.0;
    let middle = 0.5;
    let high = 1.0;

    let result = dataUrl;

    let file = originalFile;

    while (Math.abs(file.size / 1000 - targetFileSizeKb) > maxDeviation) {
        const canvas = document.createElement("canvas");
        const context = canvas.getContext("2d");
        const img = document.createElement('img');

        const promise = new Promise((resolve, reject) => {
            img.onload = () => resolve();
            img.onerror = reject;
        });

        img.src = dataUrl;

        await promise;

        canvas.width = Math.round(img.width * middle);
        canvas.height = Math.round(img.height * middle);
        context.scale(canvas.width / img.width, canvas.height / img.height);
        context.drawImage(img, 0, 0);
        file = await urltoFile(canvas.toDataURL(), 'test.png', 'image/png');

        if (file.size / 1000 < (targetFileSizeKb - maxDeviation)) {
            low = middle;
        } else if (file.size / 1000 > targetFileSizeKb) {
            high = middle;
        }

        middle = (low + high) / 2;
        result = canvas.toDataURL();
    }

    return result;
}

function urltoFile(url, filename, mimeType) {
    return (fetch(url)
            .then(function (res) {
                return res.arrayBuffer();
            })
            .then(function (buf) {
                return new File([buf], filename, {type: mimeType});
            })
    );
}

https://jsfiddle.net/qnhmytk4/3/

原文由 Stan 发布,翻译遵循 CC BY-SA 4.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题