Resize image before upload - convert canvas to a F

2019-03-08 20:44发布

Here's the code fragment I'm using now to upload multiple images using 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 before upload 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

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

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:

/** 
 * @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){}

3条回答
神经病院院长
2楼-- · 2019-03-08 21:22

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.

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

查看更多
Viruses.
3楼-- · 2019-03-08 21:23

You can call toBlob on 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.

查看更多
够拽才男人
4楼-- · 2019-03-08 21:26

Client-side image resize

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

Option 2. Use the following custom script (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);
查看更多
登录 后发表回答