Upload base64 image with Ajax

82,368

Solution 1

I finally decided to convert the base64 image to a Blob so it can be sent via an Ajax request with the formData object as follows. It saves upload bandwidth (base64 takes 33% more bits than its binary equivalent) and I couldn't find the reason for no transmission of base64 parameter (due to size limitation somewhere for sure).

The base64ToBlob function is based on this answer to another question.

function base64ToBlob(base64, mime) 
{
    mime = mime || '';
    var sliceSize = 1024;
    var byteChars = window.atob(base64);
    var byteArrays = [];

    for (var offset = 0, len = byteChars.length; offset < len; offset += sliceSize) {
        var slice = byteChars.slice(offset, offset + sliceSize);

        var byteNumbers = new Array(slice.length);
        for (var i = 0; i < slice.length; i++) {
            byteNumbers[i] = slice.charCodeAt(i);
        }

        var byteArray = new Uint8Array(byteNumbers);

        byteArrays.push(byteArray);
    }

    return new Blob(byteArrays, {type: mime});
}

My JS code:

var url = "url/action";                
var image = $('#image-id').attr('src');
var base64ImageContent = image.replace(/^data:image\/(png|jpg);base64,/, "");
var blob = base64ToBlob(base64ImageContent, 'image/png');                
var formData = new FormData();
formData.append('picture', blob);

$.ajax({
    url: url, 
    type: "POST", 
    cache: false,
    contentType: false,
    processData: false,
    data: formData})
        .done(function(e){
            alert('done!');
        });

In Symfony2 I can retrieve the image thanks to:

$picture = $request->files->get('picture');

Solution 2

Nitseg's answer works nicely. Also, I wanted to add the following lines if you must use auth token in your ajax call. Again, take a look at Nitseg's answer for more details first.

var formData = new FormData();
var token = "<YOUR-TOKEN-HERE>";
formData.append("uploadfile", mediaBlob);        

jQuery.ajax({
    url: url,
    type: "POST",
    cache: false,
    contentType: false,
    processData: false,
    data: formData,
    beforeSend: function (xhr){ 
        xhr.setRequestHeader("Authorization", "Bearer " + token); 
    }
})
.done((e) => {
    // It is done.
})
.fail((e) => {
    // Report that there is a problem!
}); 
Share:
82,368
Nitseg
Author by

Nitseg

Updated on July 09, 2022

Comments

  • Nitseg
    Nitseg almost 2 years

    My client is offering the user to pick a picture, crop and resize it and then display it (in a <img> DOM element).
    If the picture is fine, the user can upload it to the server so it can be saved.

    I would like to do the upload thanks to an Ajax request.

    I found tons of examples on the internet to upload the original image retrieved from the client PC. For instance:

    $( '#my-form' )
      .submit( function( e ) {
        $.ajax( {
          url: 'http://host.com/action/',
          type: 'POST',
          data: new FormData( this ),
          processData: false,
          contentType: false
        } );
        e.preventDefault();
      } );
    

    This works properly if I decide to upload the picture retrieved through the form input.

    In my case I want to upload the modified picture (saved in a <img> element) instead of the original one.
    This picture is stored as a base64 picture (For information: I used the croppie.js library to generate the image).

    I don't know how to upload this picture with Ajax.

    I tried to upload it as a regular parameter but on the server side the img is an empty string:

    var url = 'http://host.com/action/';
    var data = {};
    data.img = $('img#generated-image').attr('src');
    
    $.ajax({url: url, type: "POST", data: data})
      .done(function(e){
        // Do something
      });
    // RESULTS in a empty data.img on the server side.
    

    My problem being the server having an empty string when retrieving the "img" parameter. I suspect the image is maybe too big to be passed to the server or some other issues that I don't understand... .

    So I'm wondering what is the proper way to send a base64 image to the server using an Ajax request WITHOUT using a form.

    Thanks for your help.

    EDIT

    Seems to be an xmlHTTP POST parameter size issue. I tried to reduce the number of characters of the string representation of the image and the server is now able to retrieve it.

    EDIT2

    post_max_size is set to 8M in the php.ini file wheras the picture size is only 24K. So the problem is not there.
    I'm using PHP with the Symfony2 framework.
    Maybe a limitation from Symfony2.