在 JavaScript 中调整 Base-64 图像的大小而不使用画布
Posted
技术标签:
【中文标题】在 JavaScript 中调整 Base-64 图像的大小而不使用画布【英文标题】:Resize a Base-64 image in JavaScript without using canvas 【发布时间】:2014-01-24 08:03:26 【问题描述】:我需要一种无需使用 html 元素即可在 javascript 中调整图片大小的方法。
我的移动 HTML 应用程序捕获照片,然后将它们转换为 base64 字符串。此后,我需要在将它们发送到 API 之前调整它们的大小以节省存储空间。
我正在寻找一种与使用画布元素不同且更合适的方法来调整大小,有什么方法吗?
【问题讨论】:
Canvas 不适合处理图像? 您可以创建一个屏幕外画布而不将其插入 DOM。如果这很有趣,我可以举一个例子。它至少比单独使用 js 编码要快得多,因为 canvas 可以在本机编译代码中做到这一点。 Ken 听起来很棒,我会很感兴趣的! :) 我也会对此感兴趣,因为这是与 Canvas 和移动设备的交易......内存。你不能加载更大的图像,现在“更大”实际上是移动设备摄像头的大小,因为现在每个人都喜欢把 5000 万像素塞进手机:) 汤姆。我从来没有找到一个好的解决方案。我通过简单地在 phonegap 相机功能中设置图片大小和质量来解决这个问题。查看 phonegap 相机文档。通过图库导入图片时也可以。 【参考方案1】:您可以使用此处所示的原始 Base64 图像处理。
看起来很难(仅适用于 png)以及为什么许多人选择使用画布
http://blog.calyptus.eu/seb/2009/05/png-parser-in-javascript/
【讨论】:
【参考方案2】:避免主要 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 字符串,只需向其添加标头以使其成为 data-uri:
function base64ToDataUri(base64)
return 'data:image/png;base64,' + base64;
只需将image/png
部分替换为base64 字符串表示的类型(即,使其成为可选参数)。
【讨论】:
谢谢肯,我会试试这个! 对我不起作用。它创建一个 base64 字符串,但它只是透明的。 @Brettetete 如果绘制了任何图像,它们需要满足 CORS 要求。 @boop 你必须等到 img 被加载。使用 onload 事件 什么是imageToDataUri
?【参考方案3】:
Ken 的答案是正确的,但他的代码不起作用。我对其进行了一些调整,现在它可以正常工作了。调整数据 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);
【讨论】:
你没有在任何地方使用“数据”。 "img.src = datas;"在 sn-p 的底部。 我看不懂代码,我应该在“在这里使用和处理你的数据URI”中输入什么? 您的代码运行良好,可以轻松展示。通过: var newImage = document.createElement('img'); newImage.src = dataURI; document.getElementById("imgTest").innerHTML = newImage.outerHTML;这使得山雀向浏览器显示【参考方案4】:是的,你可以。这些解决方案不仅适用于将图像转换为 base64,还适用于调整大小。
-
您可以通过jpg-js将js文件转换为图像位图。并且您只能通过此库调整大小,但是如果从非常大的图像调整到非常小的大小,质量会很差。高品质的最佳方式res images 是通过jpg-js将文件转换为位图,然后通过Pica lib调整此位图的大小。
您可以通过jpg-js从文件中获取图像数据(或在画布上绘制图像),然后通过调整libpica的大小来调整canvasImageData的大小。 (适用于高分辨率图像,没有画布大小限制)
您可以使用屏幕外画布,无需将画布附加到正文,并调整图像大小。此解决方案会更快,但对于高分辨率图像(例如 6000x6000 像素)来说会是更差的解决方案。在这种情况下,结果画布可能质量很差或只是空的,或者浏览器可能会因内存限制异常而下降。 (适用于普通和小图像)
JPG-js 和 Pica 根本不会使用 dom 元素。这些库仅适用于图像数据,没有 dom 元素(画布和图像)。
关于画布,尺寸限制见post
【讨论】:
感谢您实际回答问题。我不确定为什么人们投票支持依赖画布的答案,尽管要求避免它成为问题的关键部分......这似乎是 node.js 的唯一解决方案。【参考方案5】: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
【讨论】:
这个问题特别说“没有画布”。这不是一个答案。投反对票。 @AdamBarnes 我希望你对所有其他答案都投反对票 ;) 如果你阅读了问题的前 2 或 3 个 cmets,你实际上可以读到目标是不在 DOM 上插入任何元素并在后面(后端)做。干杯伙计! 此解决方案不考虑使用移动相机上传的图像,并且可能存在方向问题,例如图片可能会旋转。 @pavloko 我写了一个图像上传工具,它确实从图像中解析了方向标签,旋转它,并设置一个新的方向标签。然后谷歌浏览器更新开始尊重方向标签。这可能不值得付出努力,因为这是最后一个添加对方向支持的流行浏览器之一。我们最终不得不将其剥离,因为与浏览器的功能作斗争是不值得的。我认为唯一的时间方向是关键的是它何时将由不尊重或不支持方向的库在后端进行操作。 @AdamBarnes 对技术问题的良好回答并不总是试图结合提问者的先入为主的概念。 OP 说他们不想要画布元素,但没有说明原因。有人可能会认为他们是在错误的观念下操作的,即您必须将 canvas 元素添加到 DOM,但事实并非如此。糟糕的投票,这是一个不错的解决方案,即使它没有严格涵盖 OP 的未指定限制。不喜欢硬编码方面。它可能不会涵盖 OP 的情况,但对于那些可以使用 canvas 元素并认为他们必须避免它的人来说,它仍然是一个很好的解决方案。【参考方案6】:我认为这种方法是解决此问题的最佳方法。
function base64Resize(sourceBase64, scale , callBack)
const _scale = scale;
var img = document.createElement('img');
img.setAttribute("src", sourceBase64);
img.onload = () =>
var canvas = document.createElement('canvas');
canvas.width = img.width * _scale;
canvas.height = img.height * _scale;
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var maxW = img.width * _scale;
var maxH = img.height * _scale;
var iw = img.width;
var ih = img.height;
var scl = Math.min((maxW / iw), (maxH / ih));
var iwScaled = iw * scl;
var ihScaled = ih * scl;
canvas.width = iwScaled;
canvas.height = ihScaled;
ctx.drawImage(img, 0, 0, iwScaled, ihScaled);
const newBase64 = canvas.toDataURL("image/jpeg", scl);
callBack(newBase64);
重要的是你应该使用img.onload
事件。
【讨论】:
问题是“不使用画布”。 我不熟悉使用回调 - 我将如何使用它? @MichaelFever:当你调用函数时,你可以附加一个函数作为第三个参数,一旦调整大小就被调用。这也可以是一个内联匿名函数,例如base64Resize("data:image/png;base64,iVBO...", 0.5, function(resizedImage) // resizedImage is variable for the resized base64 image );
。但这不是必需的。如果您不想要它,请从参数列表中删除 callBack
并删除 callBack(newBase64);
行:)以上是关于在 JavaScript 中调整 Base-64 图像的大小而不使用画布的主要内容,如果未能解决你的问题,请参考以下文章
php的base64加密,怎么调整才能和java的base64的加密结果一致呢?
在播放下一个声音之前在 javascript 中停止任何以前播放的声音(base64)的方法
如何在 JavaScript 中使用字节数组将字符串转换为 base64 编码?