在上传到服务器之前使用 JavaScript 在客户端调整图像大小

Posted

技术标签:

【中文标题】在上传到服务器之前使用 JavaScript 在客户端调整图像大小【英文标题】:Image resizing client-side with JavaScript before upload to the server 【发布时间】:2011-01-26 22:15:44 【问题描述】:

我正在寻找一种使用 javascript 调整图像客户端大小的方法(真正调整大小,而不仅仅是更改宽度和高度)。 我知道在 Flash 中可以做到这一点,但如果可能的话,我想避免它。

网络上有没有开源算法?

【问题讨论】:

对于那些仍然想知道答案的人,你可以这样做,但你需要进行一些 ajax 调用来进行图像处理。 '需要制作'?好吧,您毕竟可以在服务器上解决它,并通过 AJAX 调用透明地获取数据。但整个尝试是在客户端进行,正如 Jeremy 指出的那样,可以做到。我认为这是一个很好的例子:github.com/rossturner/html5-ImageUploader Dropzone.js 最新版本支持在上传前调整客户端图像大小。 【参考方案1】:

这里有一个要点: https://gist.github.com/dcollien/312bce1270a5f511bf4a

(一个es6版本,一个可以包含在脚本标签中的.js版本)

您可以按如下方式使用它:

<input type="file" id="select">
<img id="preview">
<script>
document.getElementById('select').onchange = function(evt) 
    ImageTools.resize(this.files[0], 
        width: 320, // maximum width
        height: 240 // maximum height
    , function(blob, didItResize) 
        // didItResize will be true if it managed to resize it, otherwise false (and will return the original file as 'blob')
        document.getElementById('preview').src = window.URL.createObjectURL(blob);
        // you can also now upload this blob using an XHR.
    );
;
</script>

它包括一堆支持检测和 polyfill,以确保它可以在尽可能多的浏览器上运行。

(它也会忽略 gif 图像 - 如果它们是动画的)

【讨论】:

我觉得你还没有得到足够的赞美——我认为它很好用而且超级简单。感谢分享! 嗯..我在这方面取得了很大的成功,但我发现我的图像(除了调整大小之外)也遭受了巨大的质量损失(以严重像素化的形式),尽管它是以正确的分辨率输出。 嗨,我需要一个像这样使用的 sn-p,我认为这非常好但是.. function(blob, didItResize) // 如果它设法调整大小,didItResize 将是真的它,否则为假(并将原始文件作为'blob'返回) document.getElementById('preview').src = window.URL.createObjectURL(blob); // 您现在也可以使用 XHR 上传此 blob。在这里我有一个问题.. 我怎样才能通过提交表单来发送这个图像。我的意思是,就像提交按钮触发的发布请求一样。你知道,通常的方式。谢谢你的要点! 对于任何质量下降(重采样)的人,更新画布上下文以将imageSmoothingEnabled 设置为 true` 并将imageSmoothingQuality 设置为high。在打字稿中,该块看起来像:const ctx = canvas.getContext('2d'); ctx.imageSmoothingEnabled = true; (ctx as any).imageSmoothingQuality = 'high'; ctx.drawImage(image, 0, 0, width, height); 有没有机会把它做成一个 npm 包?会超级棒的!【参考方案2】:

答案是肯定的——在 HTML 5 中,您可以使用 canvas 元素在客户端调整图像大小。您还可以获取新数据并将其发送到服务器。请参阅本教程:

http://hacks.mozilla.org/2011/01/how-to-develop-a-html5-image-uploader/

【讨论】:

这是一个仅链接的答案,因此应该是评论。 canvas.mozGetAsFile("foo.png");是一个不推荐使用的函数【参考方案3】:

如果您在上传之前调整大小,我刚刚发现了这个http://www.plupload.com/

它以任何可以想象的方式为您发挥所有魔力。

不幸的是,Mozilla 浏览器仅支持 HTML5 调整大小,但您可以将其他浏览器重定向到 Flash 和 Silverlight。

我刚试过,它在我的 android 上运行!

我在flash中使用http://swfupload.org/,它做得很好,但调整大小非常小。 (不记得限制)并且当 flash 不可用时不会返回 html4。

【讨论】:

当用户尝试上传一张 10mb 的照片,而该照片只会被存储为一张更小的照片时,可以在客户端调整大小。这样上传会更快。 这里的情况相同,只要您有文件输入并且用户在智能手机上并使用相机拍摄图像,现代智能手机上的图像将约为 10 mb。如果您在服务器端无论如何都在调整它的大小并且只存储它的一个小得多的版本,那么您将节省大量的蜂窝数据和加载时间,以便预先在客户端中调整大小。 小心,因为 plupload 是 AGPL。【参考方案4】:

http://nodeca.github.io/pica/demo/

在现代浏览器中,您可以使用画布加载/保存图像数据。但是,如果您在客户端调整图像大小,您应该记住以下几点:

    每个通道只有 8 位(jpeg 可以有更好的动态范围,大约 12 位)。如果您不上传专业照片,那应该没问题。 注意调整大小算法。大多数客户端缩放器使用微不足道的数学运算,结果比预期的要差。 您可能需要锐化缩小的图像。 如果您希望重用原始元数据(exif 和其他) - 不要忘记去除颜色配置文件信息。因为它是在您将图像加载到画布时应用的。

【讨论】:

【参考方案5】:

也许使用 canvas 标签(虽然它不是可移植的)。有一篇关于如何用画布here 旋转图像的博客,我想如果你可以旋转它,你可以调整它的大小。也许这可以作为一个起点。

另见this library。

【讨论】:

非常有用的例子。您可能需要在答案中添加一两个 sn-p,以防这些链接断开。【参考方案6】:

在将图像上传到服务器之前,您可以使用 javascript 图像处理框架进行客户端图像处理。

下面我使用MarvinJ根据以下页面中的示例创建了一个可运行的代码: "Processing images in client-side before uploading it to a server"

基本上我使用 Marvin.scale(...) 方法来调整图像的大小。然后,我将图像作为 blob 上传(使用方法 image.toBlob())。服务器回复并提供接收到的图像的 URL。

/***********************************************
 * GLOBAL VARS
 **********************************************/
var image = new MarvinImage();

/***********************************************
 * FILE CHOOSER AND UPLOAD
 **********************************************/
 $('#fileUpload').change(function (event) 
	form = new FormData();
	form.append('name', event.target.files[0].name);
	
	reader = new FileReader();
	reader.readAsDataURL(event.target.files[0]);
	
	reader.onload = function()
		image.load(reader.result, imageLoaded);
	;
	
);

function resizeAndSendToServer()
  $("#divServerResponse").html("uploading...");
	$.ajax(
		method: 'POST',
		url: 'https://www.marvinj.org/backoffice/imageUpload.php',
		data: form,
		enctype: 'multipart/form-data',
		contentType: false,
		processData: false,
		
	   
		success: function (resp) 
       $("#divServerResponse").html("SERVER RESPONSE (NEW IMAGE):<br/><img src='"+resp+"' style='max-width:400px'></img>");
		,
		error: function (data) 
			console.log("error:"+error);
			console.log(data);
		,
		
	);
;

/***********************************************
 * IMAGE MANIPULATION
 **********************************************/
function imageLoaded()
  Marvin.scale(image.clone(), image, 120);
  form.append("blob", image.toBlob());
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://www.marvinj.org/releases/marvinj-0.8.js"></script>
<form id="form" action='/backoffice/imageUpload.php' style='margin:auto;' method='post' enctype='multipart/form-data'>
				<input type='file' id='fileUpload' class='upload' name='userfile'/>
</form><br/>
<button type="button" onclick="resizeAndSendToServer()">Resize and Send to Server</button><br/><br/>
<div id="divServerResponse">
</div>

【讨论】:

这看起来棒极了!【参考方案7】:

根据我的经验,这个例子是上传调整大小图片的最佳解决方案:https://zocada.com/compress-resize-images-javascript-browser/

它使用 HTML5 Canvas 功能。

代码就像这样“简单”:

compress(e) 
    const fileName = e.target.files[0].name;
    const reader = new FileReader();
    reader.readAsDataURL(e.target.files[0]);
    reader.onload = event => 
        const img = new Image();
        img.src = event.target.result;
        img.onload = () => 
                const elem = document.createElement('canvas');
                const width = Math.min(800, img.width);
                const scaleFactor = width / img.width;
                elem.width = width;
                elem.height = img.height * scaleFactor;

                const ctx = elem.getContext('2d');
                // img.width and img.height will contain the original dimensions
                ctx.drawImage(img, 0, 0, width, img.height * scaleFactor);
                ctx.canvas.toBlob((blob) => 
                    const file = new File([blob], fileName, 
                        type: 'image/jpeg',
                        lastModified: Date.now()
                    );
                , 'image/jpeg', 1);
            ,
            reader.onerror = error => console.log(error);
    ;

此解决方案有两个缺点。

第一个与图像旋转有关,因为忽略了 EXIF 数据。我无法解决这个问题,并且在我的用例中并不那么重要,但很高兴听到任何反馈。

第二个缺点是缺乏对 IE/Edge 的支持(虽然不是基于 Chrome 的版本),我不会花时间讨论这个。

【讨论】:

【参考方案8】:

是的,使用现代浏览器这是完全可行的。甚至可以将文件专门作为二进制文件上传,完成任意数量的画布更改。

http://jsfiddle.net/bo40drmv/

(这个答案是对公认答案here的改进)

请记住在 PHP 中捕获处理结果提交,类似于:

//File destination
$destination = "/folder/cropped_image.png";
//Get uploaded image file it's temporary name
$image_tmp_name = $_FILES["cropped_image"]["tmp_name"][0];
//Move temporary file to final destination
move_uploaded_file($image_tmp_name, $destination);

如果有人担心 Vitaly 的观点,您可以尝试在工作的 jfiddle 上进行一些裁剪和调整大小。

【讨论】:

以上是关于在上传到服务器之前使用 JavaScript 在客户端调整图像大小的主要内容,如果未能解决你的问题,请参考以下文章

上传/下载之前/之后的客户端(javascript/jQuery)文件操作

前端防病毒扫描文件上传

#私藏项目实操分享# 使用 JavaScript 上传 PDF 和 Excel 等二进制文件到 AB

文件上传漏洞

Asp.net Core-在使用 javascript 或 C# 上传之前选择和验证 excel 文件?

如何在上传到服务器之前在 iOS 上压缩/调整图像大小?