Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>Unfortunately, this isn't possible in JavaScript without some intermediate encoding. To understand why, let's assume you base64 decoded and posted the data, like you described in your example. The first few lines in hex of a valid PHP file might look like this:</p> <pre><code>0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR 0000010: 0000 0080 0000 0080 0806 0000 00c3 3e61 ..............&gt;a </code></pre> <p>If you looked at the same range of hex of your uploaded PNG file, it would look like this:</p> <pre><code>0000000: 8950 4e47 0d0a 1a0a 0000 000d 4948 4452 .PNG........IHDR 0000010: 0000 00c2 8000 0000 c280 0806 0000 00c3 ................ </code></pre> <p>The differences are subtle. Compare the second and third columns of the second line. In the valid file, the four bytes are <code>0x00</code> <code>0x80</code> <code>0x00</code> <code>0x00</code>. In your uploaded file, the same four bytes are <code>0x00</code> <code>0xc2</code> <code>0x80</code> <code>0x00</code>. Why?</p> <p>JavaScript strings are UTF. This means that any ASCII binary values (0-127) are encoded with one byte. However, anything from 128-2047 gets <strong>two</strong> bytes. That extra <code>0xc2</code> in the uploaded file is an artifact of this multibyte encoding. If you want to know exactly why this happens, you can read more about <a href="http://en.wikipedia.org/wiki/UTF-8#Description">UTF encoding on Wikipedia</a>.</p> <p>You can't prevent this from happening with JavaScript strings, so you can't upload this binary data via AJAX without using base64.</p> <p><strong>EDIT:</strong> After some further digging, this is possible with some modern browsers. If a browser supports <code>XMLHttpRequest.prototype.sendAsBinary</code> (Firefox 3 and 4), you can use this to send the image, like so:</p> <pre><code>function postCanvasToURL(url, name, fn, canvas, type) { var data = canvas.toDataURL(type); data = data.replace('data:' + type + ';base64,', ''); var xhr = new XMLHttpRequest(); xhr.open('POST', url, true); var boundary = 'ohaiimaboundary'; xhr.setRequestHeader( 'Content-Type', 'multipart/form-data; boundary=' + boundary); xhr.sendAsBinary([ '--' + boundary, 'Content-Disposition: form-data; name="' + name + '"; filename="' + fn + '"', 'Content-Type: ' + type, '', atob(data), '--' + boundary + '--' ].join('\r\n')); } </code></pre> <p>For browsers that don't have <code>sendAsBinary</code>, but do have <code>Uint8Array</code> (Chrome and WebKit), you can polyfill it like so:</p> <pre><code>if (XMLHttpRequest.prototype.sendAsBinary === undefined) { XMLHttpRequest.prototype.sendAsBinary = function(string) { var bytes = Array.prototype.map.call(string, function(c) { return c.charCodeAt(0) &amp; 0xff; }); this.send(new Uint8Array(bytes).buffer); }; } </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload