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.
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');
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! });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With