19

I have a canvas and retrieve image data from it with help of canvas.toDataURL('image/png').

Problem: <input type="file" /> wants filepath as value instead of base64 data.

Question: How to send base64 image data to server with help of <input type="file" /> WITHOUT saving them to local file system?

My workarounds: Tried hidden input <input type="file" />, but server requires filename property

Maybe that's possible to overcome this with XmlHttpRequest?

VB_
  • 45,112
  • 42
  • 145
  • 293

3 Answers3

14

Just create a hidden input element in your form. (notice the type)

<input type="hidden" name="myHiddenField"> 

Attach your data to the value of the element before submitting.

var imageData = canvas.toDataURL('image/png');
document.getElementsByName("myHiddenField")[0].setAttribute("value", imageData);

UPDATE

If your server demands to have the parameter "filename" in the submitted data, then include that string as the name of the input element.

<input type="hidden" name="filename"/>

This will trick the form to submit your data with the "filename" parameter included in it.

If you want to use XMLHttpRequest for this, following is a sample:

//Prepare data to be sent
var imageData = canvas.toDataURL('image/png');
var params = "filename=" + imageData;

//Initiate the request
var httpRequest = new XMLHttpRequest();            
httpRequest.open('POST', 'test.php', true);

//Send proper headers
httpRequest.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
httpRequest.setRequestHeader("Content-length", params.length);
httpRequest.setRequestHeader("Connection", "close");

//Send your data
httpRequest.send(params);
Charlie
  • 22,886
  • 11
  • 59
  • 90
  • 1
    unfortunatelly that doesn't work because server requires `filename` parameter. See http://stackoverflow.com/questions/33297565/submit-hidden-input-with-filename-parameter – VB_ Oct 23 '15 at 09:11
  • The trick is that you can use name="filename" in the input element. I have updated my answer with this and also XMLHttpRequest method. – Charlie Oct 23 '15 at 11:17
  • It's much easier to use name="filename" in your input tag than creating a whole new object just in place of a single element. Anyway - the way you like it. :) – Charlie Oct 23 '15 at 12:24
  • If your server returns bad request to ``, then you have a problem somewhere else. – Charlie Oct 23 '15 at 12:31
  • I have problems because my base64 is bigger than 512kb so I get the image cut (my base64 is about 640kb), how could I do? – Mitro Dec 29 '16 at 15:33
  • You mean you get a half-image by the method `canvas.toDataURL('image/png');` ? – Charlie Dec 30 '16 at 06:56
  • Trick in a trick in a trick. Welcome to the Web programming world. – Olivier Pons Mar 25 '19 at 18:30
  • Hi @Charlie thanks for the great anwser. What if I want to send multiple `base64` images this way? then How can I distinguish what file name belongs to what hidden input? – Ahmad Mobaraki Sep 15 '19 at 16:25
2

You can use FileReader, check examples here: https://developer.mozilla.org/en-US/docs/Using_files_from_web_applications

Natural Lam
  • 732
  • 4
  • 13
0

Since the accepted answer was not created, and I missed to have an easy to copy solution, I explored @Yeldar Kurmangaliyev comment, and then I coded a working example for future visitors.

<input type="file" name="images[]" id="images" accept="'image/png'" multiple="multiple" />
    
<script>
    //Function that converts a data64 png image to a Blob object
    function dataURItoBlob(dataURI){
        var binary=atob(dataURI.split(',')[1]);
        var array=[];
        for(i=0;i<binary.length;i++){
            array.push(binary.charCodeAt(i));
        }
        return new Blob([new Uint8Array(array)],{type:'image/png'});
    }

    //Function that inserts an array of File objects inside a input type file, because HTMLInputElement.files cannot be setted directly
    function FileListItems(file_objects){
        new_input=new ClipboardEvent("").clipboardData||new DataTransfer()
        for(i=0,size=file_objects.length;i<size;++i){
            new_input.items.add(file_objects[i]);
        }
        return new_input.files;
    }               

    //An image of a small square gray and white
    const data="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASUVORK5CYII";
    //Create a Blob object
    blob=(dataURItoBlob(data));
    //Use the Blob to create a File Object
    file=new File([blob],"img.png",{type:"image/png",lastModified:new Date().getTime()});
    //Putting the File object inside an array because my input is multiple
    array_images=[file]; //You can add more File objects if your input is multiple too
    //Modify the input content to be submited
    input_images=document.querySelector("input#images")
    input_images.files=new FileListItems(array_images);
</script>
Leopoldo Sanczyk
  • 1,529
  • 1
  • 26
  • 28