53
var xhr = new XMLHttpRequest();
xhr.open('GET', 'http://static.reddit.com/reddit.com.header.png', true);

xhr.responseType = 'arraybuffer';

xhr.onload = function(e) {
  if (this.status == 200) {
    var uInt8Array = new Uint8Array(this.response);
    var byte3 = uInt8Array[4]; 

    var bb = new WebKitBlobBuilder();
    bb.append(xhr.response);
    var blob = bb.getBlob('image/png'); 
    var base64 = window.btoa(blob);
    alert(base64);

  }
};

xhr.send();

Basically, what I am trying to do here is retrieve an image, and convert it to base64.

From reading in the comments here, it states:

"Sure. After fetching a resource as an ArrayBuffer, create a blob from it. Once you have that, you could base64 encode the file/blob directly window.btoa() or FileReader.readAsDataURL()."

However, blob is just [object blob], while I need to get the binary from the image so I can convert it to base64 and display it in a img tag using data.

Anyone know how to achieve this?

Thank you in advance!

2
  • I find it very strange that you fetch image date with XHR... DOes it even work cross origin wise? Is your domain in reddit's Access-Control-Allow-Origin list? Commented Nov 5, 2011 at 19:03
  • 1
    That's just an example, the actual domain is localhost Commented Nov 5, 2011 at 19:05

4 Answers 4

76

Don't use BlobBuilder in Chrome (tested in OSX Chrome, Firefox 12, Safari 6, iOS Chrome, iOS Safari):

ex1 : http://jsfiddle.net/malraux/xGUsu/ (principle)

ex2: http://jsfiddle.net/xGUsu/78/ (working with full example)

var xhr = new XMLHttpRequest();
xhr.open('GET', 'doodle.png', true);

xhr.responseType = 'arraybuffer';

// Process the response when the request is ready.
xhr.onload = function(e) {
  if (this.status == 200) {
    // Create a binary string from the returned data, then encode it as a data URL.
    var uInt8Array = new Uint8Array(this.response);
    var i = uInt8Array.length;
    var binaryString = new Array(i);
    while (i--)
    {
      binaryString[i] = String.fromCharCode(uInt8Array[i]);
    }
    var data = binaryString.join('');

    var base64 = window.btoa(data);

    document.getElementById("myImage").src="data:image/png;base64," + base64;
  }
};

xhr.send();

Note: This code is over 7 years old at this point. While it should still function in most browsers, here's an updated version based on a suggestion by @TypeError that will only work in more modern browsers with the possible exception of iOS Safari (which may or may not support responseType = 'blob' - make sure to test!):

var xhr = new XMLHttpRequest();
xhr.open('get', 'doodle.png', true);

// Load the data directly as a Blob.
xhr.responseType = 'blob';

xhr.onload = () => {
  document.querySelector('#myimage').src = URL.createObjectURL(this.response);
};

xhr.send(); 
Sign up to request clarification or add additional context in comments.

9 Comments

xhr.responseType = 'blob' isn't implemented in chrome, it needs to be an arraybuffer. See code.google.com/p/chromium/issues/detail?id=52486
THANK YOU! Just what I was looking for! Scott A, you're a god in my eyes. Confirmed it works :)
Is there a way to do this without iterating through the data byte-by-byte?
@metadaddy: take note that the Blob constructor is only available in the newest browsers.
@ScottA: Ok, I previously didn't realize that the file we load is_not / is_different_from base64. Images are in something else, BLOB, "a collection of binary data stored as a single entity". So you must convert first into base64. Got it.
|
53

You can fetch a Blob and use window.URL.createObjectURL. This prevents building giant strings and copying everything a couple of times.

var xhr = new XMLHttpRequest();
xhr.open('GET', 'https://i.imgur.com/sBJOoTm.png', true);

xhr.responseType = 'blob';

xhr.onload = function(e) {
  if (this.status == 200) {
    var blob = this.response;
    document.getElementById("myImage").src = window.URL.createObjectURL(blob);
  }
};

xhr.onerror = function(e) {
  alert("Error " + e.target.status + " occurred while receiving the document.");
};

xhr.send();
<img id="myImage">

Example (same code): http://jsfiddle.net/ysangkok/sJxXk/86/ . Works in Firefox and Chrome 25+. And all other browsers except Opera Mini: http://caniuse.com/#search=Blob

10 Comments

The Blob constructor is only available in the newest browsers. For example, if you have to support IE8 or 9 you won't be able to use it.
@JanusTroelsen Which means absolutely nothing if you have to support one of those browsers (and it's a greater percentage than is used by Firefox regardless). :-) Incidentally, IE10 is only < 4%, so you're essentially arguing that developers should completely ignore IE, and if you look at NetApplications instead of StatCounter then IE 8+9 is 44% of the desktop. Having said that, your Blob solution doesn't work on: Safari 6.0.2 on OS X, Firefox 12 on OS X, or Safari and Chrome on my iPhone 4s either.
@JanusTroelsen And now you're making a political argument, not a practical one. Non-free vs. free isn't an option for those of us who have to work for a living in the real world, but if you're able to support yourself and stick to an unforgiving stance then more power to you. I personally had a very large corporate client that was still using IE6 internally as recently as 18 months ago, and that is now on IE8. I didn't have the option to tell them that I was only going to support Chrome or Firefox because they were free software.
@JanusTroelsen, Why not just set the responseType to blob instead of doing it indirectly via arraybuffer? See this code: jsfiddle.net/RE9YJ
In AngularJS, pass in {responseType: 'blob'} as a config option to $http.
|
10

XMLHttpRequest

var xmlhttp = new XMLHttpRequest();
xmlhttp.open('GET', 'http://RestServiceURL-Returns Image', true);
xmlhttp.setRequestHeader('Content-type','application/x-www-form-urlencoded');
xmlhttp.responseType = 'arraybuffer/blob';
xmlhttp.send();

creating blob image in 3-ways.

  • window.URL.createObjectURL
  • FileReader (caniuse)
  • Base64String

    xmlhttp.onload = function() {
        var blob = new Blob([this.response], {type: 'image/png'}); 
        console.log(blob, blob.type, this.response, typeof this.response);  
    
        var image = document.getElementById('my-image');
    
        1)image.src = window.URL.createObjectURL(blob);
    
        2)var fileReader = new window.FileReader();
        fileReader.readAsDataURL(blob);
        fileReader.onloadend = function() { 
        image.src = fileReader.result;
        }
    
        3)var base64String = btoa(String.fromCharCode.apply(null, new Uint8Array(this.response)));
        image.src = 'data:image/png;base64,'+base64String;
    };
    

Converting ArrayBuffer to Blob to ArrayBuffer

1)var dataView = new DataView(arrayBuffer);
var blob = new Blob([dataView], { type: mimeString });


2)fileReader.readAsArrayBuffer(blob);
var arrayBuffer;
fileReader.onload = function() {
    arrayBuffer = this.result;
};

1 Comment

then for saving the file in IE 11 or Egde: window.navigator.msSaveOrOpenBlob(blob, 'filename.pdf');
6

Same solution as suggested by Janus Troelsen with promise added...

Note! when using createObjectURL - don't forget to call revokeObjectURL

//  Load blob (promise)
function loadBlob( url ){
    return new Promise( (resolve, reject) => {
        const xhr = new XMLHttpRequest();
        xhr.open('GET', url, true);
        xhr.responseType = 'blob';        
        xhr.onload  = () => resolve(xhr.response);
        xhr.onerror = () => reject(xhr.statusText);        
        xhr.send();
    });
}

//  Create image from blob (createObjectURL)
function imageFromBlob( blob ){ 
    const img = new Image();
    img.onload = () => URL.revokeObjectURL(img.src);
    img.src = URL.createObjectURL(blob);    
    return img;
}


//  Create image from blob if loaded successfully
loadBlob('https://unsplash.it/960/540?random')
    .then( blob => {
        document.body.appendChild( imageFromBlob(blob) );      
    })
    .catch( error => {
        console.log('Could not load image');
    })
    


//  Alternate version adding promise to xhr
//  if you like to trigger xhr.send() yourself
function xhrBlob(url){
    const xhr = new XMLHttpRequest();
    xhr.open('GET', url, true);
    xhr.responseType = 'blob';        
    xhr.promise = new Promise((resolve, reject) => {
        xhr.onload  = () => resolve(xhr.response);
        xhr.onerror = () => reject(xhr.statusText);  
    });
    xhr.load = ( onsuccess = () => {}, onerror = () => {} ) => { 
        xhr.promise.then(onsuccess).catch(onerror);
        xhr.send();
        return xhr;
    }
    return xhr;
}


//  Using load callbacks
xhrBlob('https://unsplash.it/960/540?random')
    .load( 
        //  on sussess
        blob => {
            document.body.appendChild( imageFromBlob(blob) );      
        },
        //  on error
        error => {
            console.log('Could not load image');
        }
    );
    
 //  Using promise (delayed)
const image = xhrBlob('https://unsplash.it/960/540?random');

    //  Promise handlers
    image.promise
    .then( blob => {
        document.body.appendChild( imageFromBlob(blob) );      
    })
    .catch( error => {
        console.log('Could not load image');
    });
 
 //  Load image (will trigger promise handlers)
 setTimeout(image.load, 3000);
img {
  width: 100%;
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.