上传前调整图像大小 - 将画布转换为文件对象

问题描述 投票:0回答:4

这是我现在使用 HTML5 文件 API 上传多个图像的代码片段:

/**
 * @param {FileList} files
 */
upload: function(files){
    nfiles = files.length;

    for (var i = 0; i < nfiles; i++) {
        /** @var file File **/
        var file = files[i];

        var xhr = new XMLHttpRequest();

        xhr.open("POST", settings.post_upload, true);
        xhr.setRequestHeader("X-Requested-With", "XMLHttpRequest");
        xhr.upload.filenumb = i;
        xhr.filenumb = i;
        xhr.upload.filename = file.name;

        var nef = new FormData();
        nef.append("folder", settings.folder);
        nef.append("file_element", settings.file_elem);
        nef.append("udata", settings.user_data);
        nef.append(settings.file_elem, file);
        xhr.send(nef);

    }
}

我想在使用画布对象上传之前调整图像大小,但没有这方面的经验,我不确定如何使用技术更新代码,例如这里描述的一个:HTML5 Pre-resize images before upload

canvas.toDataURL("image/png");

 将返回一个编码字符串。但我需要发布 
File
 对象。 

编辑

如何为大多数现代浏览器编写(合理的)跨浏览器功能,以便在上传之前调整文件大小,以透明方式处理 jpg、png 和 gif:

/** * @param {File} file * @param int max_width * @param int max_height * @param float compression_ratio * @returns File */ function resize(file, max_width, max_height, compression_ratio){}
    
javascript html file-upload html5-canvas
4个回答
29
投票
尝试这样的事情:

function resize(file, max_width, max_height, compression_ratio, imageEncoding){ var fileLoader = new FileReader(), canvas = document.createElement('canvas'), context = null, imageObj = new Image(), blob = null; //create a hidden canvas object we can use to create the new resized image data canvas.id = "hiddenCanvas"; canvas.width = max_width; canvas.height = max_height; canvas.style.visibility = "hidden"; document.body.appendChild(canvas); //get the context to use context = canvas.getContext('2d'); // check for an image then //trigger the file loader to get the data from the image if (file.type.match('image.*')) { fileLoader.readAsDataURL(file); } else { alert('File is not an image'); } // setup the file loader onload function // once the file loader has the data it passes it to the // image object which, once the image has loaded, // triggers the images onload function fileLoader.onload = function() { var data = this.result; imageObj.src = data; }; fileLoader.onabort = function() { alert("The upload was aborted."); }; fileLoader.onerror = function() { alert("An error occured while reading the file."); }; // set up the images onload function which clears the hidden canvas context, // draws the new image then gets the blob data from it imageObj.onload = function() { // Check for empty images if(this.width == 0 || this.height == 0){ alert('Image is empty'); } else { context.clearRect(0,0,max_width,max_height); context.drawImage(imageObj, 0, 0, this.width, this.height, 0, 0, max_width, max_height); //dataURItoBlob function available here: // http://stackoverflow.com/questions/12168909/blob-from-dataurl // add ')' at the end of this function SO dont allow to update it without a 6 character edit blob = dataURItoBlob(canvas.toDataURL(imageEncoding)); //pass this blob to your upload function upload(blob); } }; imageObj.onabort = function() { alert("Image load was aborted."); }; imageObj.onerror = function() { alert("An error occured while loading image."); }; }

请注意:

使用文件加载器和加载图像意味着存在一些延迟,因此该函数是异步的,因此尝试简单地返回 blob 数据是行不通的。您需要等待加载发生,然后才能使用加载的数据并为每个文件触发对上传函数的调用。

文件加载器也可能存在一些浏览器兼容性问题,但我认为这在客户端以任何其他方式都是不可能的。


4
投票

客户端图像调整大小

选项 1.使用 Pica 库 (

https://github.com/nodeca/pica)

选项 2.使用以下自定义脚本 (

http://jsfiddle.net/cL3hapL4/2/)

var file = document.getElementById('imageUpload'); var mime = "image/jpeg"; var max_width = 100; var max_height = 100; var canvas = document.createElement("canvas"); var ctx = canvas.getContext("2d"); var img = new Image(); img.onload = function () { // Clear canvas, and resize image ctx.clearRect(0, 0, max_width, max_height); ctx.drawImage(img, 0, 0, img.width, img.height, // size of image 0, 0, max_width, max_height // size of canvas ); // Get image from canvas as a dataURI, and convert to a blob object var dataURI = canvas.toDataUrl(mime); // Note: This function can be replaced with canvas.toBlob(), // once supported by browsers. // --- var image_blob = (function () { var binary = atob(dataURI.split(',')[1]); var array = []; for(var i = 0; i < binary.length; i++) { array.push(binary.charCodeAt(i)); } return new Blob([new Uint8Array(array)], {type: mime}); })(); // --- // Attach blob-object (contains our image) to form object var form = new Form(); form.append("image", image_blob); // Send AJAX request with multi-part data var xhr = new XMLHttpRequest(); xhr.open('POST', '/route', true); xhr.send(form); // jQuery version //$.ajax({ // type: "POST", // url: "/route", // data: form, // processData: false, // contentType: false //}) //.done(function (response) { // console.log(response); //}); }; img.src = URL.createObjectURL(file);
    

2
投票
您可以在

toBlob

 元素上调用 
<canvas>
。这将返回一个 
Blob
,它是 
File
 的父接口。然后您可以通过 XHR2 将此对象发送到您的服务器。


0
投票
我为此发布了一个开源模块,这将任务减少到:

let file = input.files[i]; // Limit the maximum size file = await scale(file, { maxWidth: 1600, maxHeight: 1600 });
其他都不需要改变。您还可以重新映射内容类型,并在无法正常工作时启用后备上传原始内容,尽管在 2023 年拥有制造商支持的所有浏览器中的支持都很强大。

您可以在这里找到@apostrophecms/scale

模块。

© www.soinside.com 2019 - 2024. All rights reserved.