Convert HTML5 Canvas into File to be uploaded?

后端 未结 5 1675
生来不讨喜
生来不讨喜 2020-11-28 03:54

The standard HTML file upload works as follows:



        
相关标签:
5条回答
  • 2020-11-28 04:07

    This is what worked for me in the end.

    canvas.toBlob((blob) => {
      let file = new File([blob], "fileName.jpg", { type: "image/jpeg" })
    }, 'image/jpeg');
    
    
    0 讨论(0)
  • 2020-11-28 04:09

    Currently in spec (very little support as of april '17)

    Canvas.toBlob();

    https://developer.mozilla.org/en-US/docs/Web/API/HTMLCanvasElement/toBlob

    EDIT :

    The link provides a polyfill (which seems to be slower from the wording), which code is roughtly equivalent to the @pixelomo answer, but with the same api as the native toBlob method :

    A low performance polyfill based on toDataURL :

    if (!HTMLCanvasElement.prototype.toBlob) {
      Object.defineProperty(HTMLCanvasElement.prototype, 'toBlob', {
        value: function (callback, type, quality) {
          var canvas = this;
          setTimeout(function() {
    
        var binStr = atob( canvas.toDataURL(type, quality).split(',')[1] ),
            len = binStr.length,
            arr = new Uint8Array(len);
    
        for (var i = 0; i < len; i++ ) {
          arr[i] = binStr.charCodeAt(i);
        }
    
        callback( new Blob( [arr], {type: type || 'image/png'} ) );
    
          });
        }
      });
    }
    

    To be used this way :

    canvas.toBlob(function(blob){...}, 'image/jpeg', 0.95); // JPEG at 95% quality
    

    or

    canvas.toBlob(function(blob){...}); // PNG
    
    0 讨论(0)
  • 2020-11-28 04:17

    Another solution: send the data in var url in a hidden field, decode and save it on the server.

    Example in Python Django:

    if form.is_valid():
        url = form.cleaned_data['url']
        url_decoded = b64decode(url.encode())        
        content = ContentFile(url_decoded) 
        your_model.model_field.save('image.png', content)
    
    0 讨论(0)
  • 2020-11-28 04:29

    For security reasons, you can't set the value of a file-input element directly.

    If you want to use a file-input element:

    1. Create an image from the canvas (as you've done).
    2. Display that image on a new page.
    3. Have the user right-click-save-as to their local drive.
    4. Then they can use your file-input element to upload that newly created file.

    Alternatively, you can use Ajax to POST the canvas data:

    You asked about blob:

    var blobBin = atob(dataURL.split(',')[1]);
    var array = [];
    for(var i = 0; i < blobBin.length; i++) {
        array.push(blobBin.charCodeAt(i));
    }
    var file=new Blob([new Uint8Array(array)], {type: 'image/png'});
    
    
    var formdata = new FormData();
    formdata.append("myNewFileName", file);
    $.ajax({
       url: "uploadFile.php",
       type: "POST",
       data: formdata,
       processData: false,
       contentType: false,
    }).done(function(respond){
      alert(respond);
    });
    

    Note: blob is generally supported in the latest browsers.

    0 讨论(0)
  • 2020-11-28 04:29

    The canvas image needs to be converted to base64 and then from base64 in to binary. This is done using .toDataURL() and dataURItoBlob()

    It was a pretty fiddly process which required piecing together several SO answers, various blog posts and tutorials.

    I've created a tutorial you can follow which walks you through the process.

    In response to Ateik's comment here's a fiddle which replicates the original post in case you're having trouble viewing the original link. You can also fork my project here.

    There's a lot of code but the core of what I'm doing is take a canvas element:

    <canvas id="flatten" width="800" height="600"></canvas>
    

    Set it's context to 2D

    var snap = document.getElementById('flatten');
    var flatten = snap.getContext('2d');
    

    Canvas => Base64 => Binary

    function postCanvasToURL() {
      // Convert canvas image to Base64
      var img = snap.toDataURL();
      // Convert Base64 image to binary
      var file = dataURItoBlob(img);
    }
    
    function dataURItoBlob(dataURI) {
    // convert base64/URLEncoded data component to raw binary data held in a string
    var byteString;
    if (dataURI.split(',')[0].indexOf('base64') >= 0)
        byteString = atob(dataURI.split(',')[1]);
    else
        byteString = unescape(dataURI.split(',')[1]);
    // separate out the mime component
    var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0];
    // write the bytes of the string to a typed array
    var ia = new Uint8Array(byteString.length);
    for (var i = 0; i < byteString.length; i++) {
        ia[i] = byteString.charCodeAt(i);
    }
    return new Blob([ia], {type:mimeString});
    }

    You could stop at base64 if that's all you need, in my case I needed to convert again to binary so that I could pass the data over to twitter (using OAuth) without use of a db. It turns out you can tweet binary which is pretty cool, twitter will convert it back in to an image.

    0 讨论(0)
提交回复
热议问题