16

I'd like to build a simple HTML page that includes JavaScript to perform a form POST with image data that is embedded in the HTML vs a file off disk.

I've looked at this post which would work with regular form data but I'm stumped on the image data.

JavaScript post request like a form submit

Community
  • 1
  • 1
andyknas
  • 1,846
  • 2
  • 15
  • 28
  • To be clear: you want to simulate in JavaScript the manual submission of a form that includes a file upload input control (of an image file). Is that right? – Hew Wolff Sep 12 '12 at 16:22
  • If you have control over the application that receives the POST, you could send the image data as a large string parameter in the form (for example in Base64 encoding). But it sounds like you don't have that control, right? – Hew Wolff Sep 12 '12 at 16:26
  • I do not have control over the server-side coding. My goal is to perform the upload entirely thru JavaScript so the process is automatic when the HTML page is loaded as the image is not important, but additional data in the URL is. Unfortunately, the image data is necessary on the receiving end. – andyknas Sep 12 '12 at 17:09
  • Is your JavaScript served from the _same origin_ as the images? – Joe Coder Sep 15 '12 at 07:01
  • You mean something like this? http://aloha-editor.org/ with the image editor http://labs.tapo-it.com/aloha/aloha-imageplugin/examples/example.html – yunzen Sep 21 '12 at 13:31

2 Answers2

26

** UPDATE ** Feb. 2014 **

New and improved version available as a jQuery plugin: https://github.com/CoeJoder/jquery.image.blob

Usage:

$('img').imageBlob().ajax('/upload', {
    complete: function(jqXHR, textStatus) { console.log(textStatus); } 
});



Requirements

Thus the browser requirements are:

  • Chrome: 20+
  • Firefox: 13+
  • Internet Explorer: 10+
  • Opera: 12.5+
  • Safari: 6+

Note: The images must be of the same-origin as your JavaScript, or else the browser security policy will prevent calls to canvas.toDataURL() (for more details, see this SO question: Why does canvas.toDataURL() throw a security exception?). A proxy server can be used to circumvent this limitation via response header injection, as described in the answers to that post.

Here is a jsfiddle of the below code. It should throw an error message, because it's not submitting to a real URL ('/some/url'). Use firebug or a similar tool to inspect the request data and verify that the image is serialized as form data (click "Run" after the page loads):

POST data

Example Markup

<img id="someImage" src="../img/logo.png"/>

The JavaScript

(function() {
    // access the raw image data
    var img = document.getElementById('someImage');
    var canvas = document.createElement('canvas');
    var ctx = canvas.getContext('2d');
    canvas.width = img.width;
    canvas.height = img.height;
    ctx.drawImage(img, 0, 0);
    var dataUrl = canvas.toDataURL('image/png');
    var blob = dataUriToBlob(dataUrl);

    // submit as a multipart form, along with any other data
    var form = new FormData();
    var xhr = new XMLHttpRequest();
    xhr.open('POST', '/some/url', true);    // plug-in desired URL
    xhr.onreadystatechange = function() {
        if (xhr.readyState == 4) {
            if (xhr.status == 200) {
                alert('Success: ' + xhr.responseText);
            } else {
                alert('Error submitting image: ' + xhr.status);
            }
        }
    };
    form.append('param1', 'value1');
    form.append('param2', 'value2');
    form.append('theFile', blob);
    xhr.send(form);

    function dataUriToBlob(dataURI) {
        // serialize the base64/URLEncoded data
        var byteString;
        if (dataURI.split(',')[0].indexOf('base64') >= 0) {
            byteString = atob(dataURI.split(',')[1]);
        }
        else {
            byteString = unescape(dataURI.split(',')[1]);
        }

        // parse the mime type
        var mimeString = dataURI.split(',')[0].split(':')[1].split(';')[0]

        // construct a Blob of the image data
        var array = [];
        for(var i = 0; i < byteString.length; i++) {
            array.push(byteString.charCodeAt(i));
        }
        return new Blob(
            [new Uint8Array(array)],
            {type: mimeString}
        );
    }
})();

References

SO: 'Convert DataURI to File and append to FormData

Community
  • 1
  • 1
Joe Coder
  • 4,136
  • 26
  • 38
  • I used the same above given code but it shows me "ArrayBuffer is deprecated in XMLHttpRequest.send(). Use ArrayBufferView instead." Please help me out. Thanks in advance :) – V_PULL Feb 06 '14 at 09:28
  • You must not be using the same code. I'm using [XMLHttpRequest.send(:FormData)](https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest#Browser_Compatibility). The FormData contains a Blob, and the Blob is constructed using a TypedArray, "Uint8Array" [(which is an ArrayBufferView)](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Typed_arrays#Buffers_and_views.3A_typed_array_architecture). I'm not using an ArrayBuffer at all. – Joe Coder Feb 06 '14 at 19:01
  • Worked great. Too bad that `dataUriToBlob` isn't a part of jquery or javascript. – Mike Purcell May 21 '15 at 22:58
0

Assuming that you are talking about embedded image data like http://en.wikipedia.org/wiki/Data_URI_scheme#HTML

****If my assumption is incorrect, please ignore this answer.**

You can send it as JSON using XMLHttpRequest. Here is sample code: (you may want to remove the header part ('data:image/png;base64,') before sending)

Image

<img id="myimg" src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUA
AAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO
9TXL0Y4OHwAAAABJRU5ErkJggg==" alt="Red dot">

Button

<input id="subbtn" type="button" value="sub" onclick="sendImg()"></input>

Script

function sendImg() {
    var dt = document.getElementById("myimg").src;
    var xhr = new XMLHttpRequest();
    xhr.open("POST", '/Home/Index', true); //put your URL instead of '/Home/Index'
    xhr.onreadystatechange = function () {
        if (xhr.readyState === 4) { //4 means request finished and response is ready
            alert(xhr.responseText);
        }
    };
    var contentType = "application/json";
    xhr.setRequestHeader("Content-Type", contentType);

    for (var header in this.headers) {
        xhr.setRequestHeader(header, headers[header]);
    }

    // here's our data variable that we talked about earlier
    var data = JSON.stringify({ src: dt });

    // finally send the request as binary data
    xhr.send(data);
}

EDIT

As @JoeCoder suggests, instead of json, you can also use a FormData object and send in Binary format. Check his answer for more details.

Community
  • 1
  • 1
prashanth
  • 1,989
  • 11
  • 11
  • This requires special server-side processing. Instead, use the FormData object to embed the binary data in a standardized way. – Joe Coder Sep 21 '12 at 20:39