How do I load binary image data using Javascript and XMLHttpRequest?
-
I was trying to load an image client side and base64 encode the bytes returned by the server in order to pass it off to perform some processing. IE has a RequestBody property of the XMLHttpRequest object, but I can't seem to use it, and RequestText is truncated. In Firefox, RequestText is there, but seems corrupted.
-
Answer:
After a few days' effort I was able to make this work, although information on the Internet for doing such binary manipulation is fairly scarce. I think it may be useful for others, especially when dealing with Data URIs, so I've detailed my work here: http://emilsblog.lerch.org/2009/07/javascript-hacks-using-xhr-to-load.html
Emil Lerch at Stack Overflow Visit the source
Other answers
Here's how I did it. This technique is provided in an answer to another SO question, but it's also relevant here. I didn't want to base64 encode anything. I wanted to download and parse binary files in the browser via Javascript, without modifying the server to encode them specially. I found that in Firefox, by coercing the mimetype of the response via overrideMimeType(), I could use XMLHttpRequest.responseText. On IE, it's different because: responseText on IE truncates at the first zero. For binary streams this is a big problem. there is no XMLHttpRequest.overrideMimeType(), to force IE to treat binary streams as text. while there is a XMLHttpRequest.responseBody (IE only!) that is specifically designed to be used with binary data streams, maddeningly that property is not usable from Javascript. Therefore, the need is to convert IE's responseBody property into a thing that looks like responseText from FireFox, with the mime-type coercion. This is possible using injected VBScript. To make it cross-browser, you need to just pack up the browser-specific logic in a conditional. This is what I used: // one-time code if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { var IEBinaryToArray_ByteStr_Script = "<!-- IEBinaryToArray_ByteStr -->\r\n"+ "<script type='text/vbscript'>\r\n"+ "Function IEBinaryToArray_ByteStr(Binary)\r\n"+ " IEBinaryToArray_ByteStr = CStr(Binary)\r\n"+ "End Function\r\n"+ "Function IEBinaryToArray_ByteStr_Last(Binary)\r\n"+ " Dim lastIndex\r\n"+ " lastIndex = LenB(Binary)\r\n"+ " if lastIndex mod 2 Then\r\n"+ " IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n"+ " Else\r\n"+ " IEBinaryToArray_ByteStr_Last = "+'""'+"\r\n"+ " End If\r\n"+ "End Function\r\n"+ "</script>\r\n"; // inject VBScript document.write(IEBinaryToArray_ByteStr_Script); } // each time you make a request for a binary resource: var req = (function() { if (window.XMLHttpRequest) { return new window.XMLHttpRequest(); } else { try { return new ActiveXObject("MSXML2.XMLHTTP"); } catch(ex) { return null; } } })(); var fileContents = ""; var filesize = -1; var readByteAt = function(i){ return fileContents.charCodeAt(i) & 0xff; }; req.open("GET", url, true); if(/msie/i.test(navigator.userAgent) && !/opera/i.test(navigator.userAgent)) { // IE-specific logic here // helper to convert from responseBody to a "responseText" like thing var convertResponseBodyToText = function (binary) { var byteMapping = {}; for ( var i = 0; i < 256; i++ ) { for ( var j = 0; j < 256; j++ ) { byteMapping[ String.fromCharCode( i + j * 256 ) ] = String.fromCharCode(i) + String.fromCharCode(j); } } var rawBytes = IEBinaryToArray_ByteStr(binary); var lastChr = IEBinaryToArray_ByteStr_Last(binary); return rawBytes.replace(/[\s\S]/g, function( match ) { return byteMapping[match]; }) + lastChr; }; req.setRequestHeader("Accept-Charset", "x-user-defined"); req.onreadystatechange = function(event){ if (req.readyState == 4) { if (req.status == 200) { fileContents = convertResponseBodyToText(req.responseBody); fileSize = fileContents.length-1; // invoke a callback here, if you like... } else{ alert("download failed, status " + req.status); } } }; req.send(); } else { // ff/Gecko/Webkit specific stuff here req.onreadystatechange = function(aEvt) { if (req.readyState == 4) { // completed if(req.status == 200){ // status == OK fileContents = binStream.req.responseText; filesize = fileContents.length; // invoke a callback here, if you like... } else { alert("download failed, status " + req.status); } } }; // coerce response type req.overrideMimeType('text/plain; charset=x-user-defined'); req.send(null); } ...then call readByte(i) to get the byte at the ith position in the binary file. Good luck. http://miskun.com/javascript/internet-explorer-and-binary-files-data-access/ for the VBScript conversion logic.
Cheeso
You could have the server return base64 text, rather than doing that encoding client side. For example, (in ASP.NET) a request to /ImageAsBase64.ashx?file=/images/myimage.png could be coded to read the file, base64encode it, and stream it as a response. It's really going to be pretty much the same thing in PHP or whatever.
Clyde
If you're using COTS, you could always set up an intermediate gateway wherein the request is made and transformed (base64 encoded in this case) into something more palatable before being returned to the client.
Justin Johnson
Related Q & A:
- How to connect to a Pervasive Database using javascript?Best solution by Stack Overflow
- How to dynamically load an image in Crystal 9?Best solution by codeproject.com
- How to get current YouTube video url using JavaScript?Best solution by Stack Overflow
- How to deal with dynamic JSON data using AngularJS?Best solution by Stack Overflow
- How can I open binary files, that are email attachments?Best solution by Yahoo! Answers
Just Added Q & A:
- How many active mobile subscribers are there in China?Best solution by Quora
- How to find the right vacation?Best solution by bookit.com
- How To Make Your Own Primer?Best solution by thekrazycouponlady.com
- How do you get the domain & range?Best solution by ChaCha
- How do you open pop up blockers?Best solution by Yahoo! Answers
For every problem there is a solution! Proved by Solucija.
-
Got an issue and looking for advice?
-
Ask Solucija to search every corner of the Web for help.
-
Get workable solutions and helpful tips in a moment.
Just ask Solucija about an issue you face and immediately get a list of ready solutions, answers and tips from other Internet users. We always provide the most suitable and complete answer to your question at the top, along with a few good alternatives below.