22

Using Javascript, I'm making an AJAX call to a WCF service, and it is returning a byte array. How can I convert that to an image and display it on the web page?

Magnus Lind Oxlund
  • 304
  • 1
  • 6
  • 19
KevinDeus
  • 11,988
  • 20
  • 65
  • 97
  • 1
    I wonder, can you modify the response type from the service? Is it just pure bytes only? – Lloyd Dec 30 '10 at 16:04
  • Even if you can "convert it to an image" I'm not sure how you'd place it into the DOM. It would need to be referenced as a resource somehow. Interesting question. – David Dec 30 '10 at 16:06
  • Added a modern answer that doesn't require any conversion from/to base64. Super efficient. – oligofren Aug 22 '19 at 10:11
  • @David The easiest answer is to just do it like we reference all binary blobs that we display as images: ``. If the content type has been set correctly that will display the image. The more complicated answer, in case changing the server isn't an option, is doing what I propose below. – oligofren Aug 30 '19 at 11:54

8 Answers8

19

I realize this is an old thread, but I managed to do this through an AJAX call on a web service and thought I'd share...

  • I have an image in my page already:

     <img id="ItemPreview" src="" />
    
  • AJAX:

    $.ajax({
            type: 'POST',
            contentType: 'application/json; charset=utf-8',
            dataType: 'json',
            timeout: 10000,
            url: 'Common.asmx/GetItemPreview',
            data: '{"id":"' + document.getElementById("AwardDropDown").value + '"}',
            success: function (data) {
                if (data.d != null) {
                    var results = jQuery.parseJSON(data.d);
                    for (var key in results) {
                        //the results is a base64 string.  convert it to an image and assign as 'src'
                        document.getElementById("ItemPreview").src = "data:image/png;base64," + results[key];
                    }
                }
            }
        });
    

My 'GetItemPreview' code queries a SQL server where I have an image stored as a base64 string and returns that field as the 'results':

     string itemPreview = DB.ExecuteScalar(String.Format("SELECT [avatarImage] FROM [avatar_item_template] WHERE [id] = {0}", DB.Sanitize(id)));
     results.Add("Success", itemPreview);
     return json.Serialize(results);

The magic is in the AJAX call at this line:

     document.getElementById("ItemPreview").src = "data:image/png;base64," + results[key];

Enjoy!

Nicolai Dutka
  • 340
  • 1
  • 4
  • 16
  • 1. This doesn't answer the question at all. 2. Don't do this: you increase the payload size by 30%, get a huge increase in memory usage on the client (totally unneccesary!) and complicate the client logic. If you have your images on the server, just store them as byte arrays and serve them as a normal bytestream. Then your entire logic is `src="/api/images/" + image.id`. Your browser doesn't care if the image is stored on file or in a database. – oligofren Aug 30 '19 at 11:48
7

Here is JavaScript source to decode PNG, JPEG and GIF image bytes, using the Data URI scheme:

Images.decodeArrayBuffer = function(buffer, onLoad) {
    var mime;
    var a = new Uint8Array(buffer);
    var nb = a.length;
    if (nb < 4)
        return null;
    var b0 = a[0];
    var b1 = a[1];
    var b2 = a[2];
    var b3 = a[3];
    if (b0 == 0x89 && b1 == 0x50 && b2 == 0x4E && b3 == 0x47)
        mime = 'image/png';
    else if (b0 == 0xff && b1 == 0xd8)
        mime = 'image/jpeg';
    else if (b0 == 0x47 && b1 == 0x49 && b2 == 0x46)
        mime = 'image/gif';
    else
        return null;
    var binary = "";
    for (var i = 0; i < nb; i++)
        binary += String.fromCharCode(a[i]);
    var base64 = window.btoa(binary);
    var image = new Image();
    image.onload = onLoad;
    image.src = 'data:' + mime + ';base64,' + base64;
    return image;
}
Adam Gawne-Cain
  • 1,347
  • 14
  • 14
6

Instead of calling the service with AJAX, use Javascript to build an image element and point it to the service directly...

var img = document.createElement("IMG");
img.src = "http://url/to/service";
img.alt = "ALT TEXT";
document.body.appendChild(img);

Just make sure the service sets the content type properly.

Josh Stodola
  • 81,538
  • 47
  • 180
  • 227
  • 1
    ok.. that *almost* works. Remember I said that I'm making a call to a WCF service. What I get back looks like: "{"d":[66,77,230,11,0,0,0,0,0,0,54,0,0,0,40,0,0,0,22,0,0,0,34,0,0,0,1... etc".. This is probably because I have the WebInvoke Attribute set as: [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Json, RequestFormat = WebMessageFormat.Json)] So the question is.. what should the WCF WebInvokeAttribute look like? – KevinDeus Dec 30 '10 at 17:36
  • 1
    @Kevin You may need a more HTTP friendly wrapper for your service. For instance, a generic handler that invokes the service and streams the byte array using `Response.BinaryWrite` and sets content type to "image/jpeg". That would work. – Josh Stodola Dec 30 '10 at 18:16
  • hmm. I got as far as changing the OutgoingResponse.ContentType in the web service (WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg";), but that still wouldn't do it. In order to make what you are saying work, I changed the output of the service function to System.Io.Stream – KevinDeus Dec 30 '10 at 22:14
  • [OperationContract] [WebInvoke(Method = "GET", BodyStyle = WebMessageBodyStyle.WrappedRequest, ResponseFormat = WebMessageFormat.Xml, RequestFormat = WebMessageFormat.Xml)] public Stream QuestionDataFile() { FileStream fs = File.OpenRead(@"C:\D.jpg"); WebOperationContext.Current.OutgoingResponse.ContentType = "image/jpeg"; return fs; } – KevinDeus Dec 30 '10 at 22:16
6

Late to the party but if your response looks like

[137,80,78,71,13,10,26,10,0,...]

you can use this:

<img id="image" src="" />
var imgsrc = "data:image/png;base64," + btoa(String.fromCharCode.apply(null, new Uint8Array([137,80,78,71,13,10,26,10,0,...])));

document.getElementById('image').src = imgsrc;
Joel'-'
  • 652
  • 1
  • 5
  • 17
5

Converting a byte array to base64 when you have the binary byte array (not a JSON string array of the byte values) is ridiculously expensive, and more importantly; it is totally unnecessary work, as you do not have to do convert it at all in modern browsers! The static URL.createObjectURL method creates a DOMString, a short browser-specific url, from the byte array, and you can use the resulting short string in img.src or similar.

This is infinitely faster than solutions that require chaining TextEncoder and btoa when all you need is to display an image received in a byte array form.

var blob = new Blob( [ uint8ArrayBuffer ], { type: "image/jpeg" } );
var imageUrl = URL.createObjectURL( blob );

This is using HTML5 APIs, and so will not work on Node or other JS based servers, of course.

// Simulate a call to Dropbox or other service that can
// return an image as an ArrayBuffer.
var xhr = new XMLHttpRequest();

// Use PlaceKitten as a sample image to avoid complicating
// this example with cross-domain issues.
xhr.open( "GET", "https://placekitten.com/200/140", true );

// Ask for the result as an ArrayBuffer.
xhr.responseType = "arraybuffer";

xhr.onload = function( e ) {
    // Obtain a blob: URL for the image data.
    var arrayBufferView = new Uint8Array( this.response );
    var blob = new Blob( [ arrayBufferView ], { type: "image/jpeg" } );
    var urlCreator = window.URL || window.webkitURL;
    var imageUrl = urlCreator.createObjectURL( blob );
    var img = document.querySelector( "#photo" );
    img.src = imageUrl;
};

xhr.send();
<h1>Demo of displaying an ArrayBuffer</h1>
<p><a href="http://jsfiddle.net/Jan_Miksovsky/yy7Zs/">Originally made by Jan Miksovsky</p>
<img id="photo"/>
oligofren
  • 20,744
  • 16
  • 93
  • 180
0

Just send it back as a Base64 then just:

var sig = new Image;
sig.src = 'data:image/png;base64,' + $('#Signature').val();

In my case I am using a Hidden Input with an Id of Signature to store that Base64 data

Serj Sagan
  • 28,927
  • 17
  • 154
  • 183
0

You would probably want to create a data-uri from your data and put it in the src attribute of an img element

http://en.wikipedia.org/wiki/Data_URI_scheme

kioopi
  • 2,170
  • 2
  • 18
  • 26
-3

Using jQuery as an example:

var myImage = $('< img src="data:image/jpg; base64," + bytesarray + "/>"');
Meyer
  • 1,662
  • 7
  • 21
  • 20
molham556
  • 183
  • 1
  • 6