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

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15990946/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-29 07:31:38  来源:igfitidea点击:

Resize image before upload - convert canvas to a File object

javascripthtmlfile-uploadhtml5-canvas

提问by Sfisioza

Here's the code fragment I'm using now to upload multiple images using HTML5 File API:

这是我现在使用 HTML5 File 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);

    }
}

I'd like to resize the images beforeupload using canvas object, but not having experience with this, I'm not sure how can update the code using techniques, e.g. the one described here: HTML5 Pre-resize images before uploading

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

canvas.toDataURL("image/png");will return an encoded string. But I need to post the Fileobject.

canvas.toDataURL("image/png");将返回一个编码字符串。但我需要发布File对象。

Edit

编辑

How would you write (reasonably) cross browser function for most modern browsers to resize the File before upload, handling jpg,png and gifs with transparency:

您将如何为大多数现代浏览器编写(合理的)跨浏览器功能,以在上传之前调整文件大小,处理透明的 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){}

回答by Brendon John Wildbore

Try something like this:

尝试这样的事情:

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.");
    };

}

Please note:

请注意:

Working with fileloaders and loading images means there are some delays and the function is therefore asynchronous so trying to simply return the blob data wont work. You need to wait for the loading to occur before you can use the loaded data and fire off a call to your upload function for EACH file.

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

Also fileloader may have some browser compatability issues but I don't think this is possible any other way client side.

此外,fileloader 可能有一些浏览器兼容性问题,但我认为这不可能以任何其他方式客户端。

回答by tfmontague

Client-side image resize

客户端图像调整大小

Option 1. Use the Pica library (https://github.com/nodeca/pica)

选项 1. 使用 Pica 库 ( https://github.com/nodeca/pica)

Option 2. Use the following custom script (http://jsfiddle.net/cL3hapL4/2/)

选项 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);

回答by Ray Nicholus

You can call toBlobon the <canvas>element. This will return a Blob, which is the parent interface of File. You can then send this object to your server via XHR2.

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