Converting images to base64 encoding

1,304 views
Skip to first unread message

Miguel Guedes

unread,
Feb 12, 2015, 4:15:27 PM2/12/15
to chromium-...@chromium.org

I am working on a project that requires certain images that a user selects to be processed such that their image data is encoded in base64. Ideally I would like to do this from within a content script but can't because of CORS * so I have no other option but to delegate this to the background page. Now, since send.message only accepts JSON serializable data, I am unable to send a direct reference to an HTMLImageElement instance to the background page and have to pass its src attribute instead. In the background page, I then instantiate an Image, set its src element and carry out the required processing once the onload event fires.

My question is this: what will the browser do when the Image instance above is created and its src set? Will it simply retrieve the image data from its cache store, since it's just been loaded in a tab, or will the browser attempt to re-download the image? The latter isn't desirable since there is a chance that the image won't be available due to hot linking countermeasures by some servers or some other techniques.

What real options have I got to ensure that the same image that was loaded in the tab is made available to the background page?


* When attempting to retrieve image data in base64 encoding via canvas trickery in the content script, I run into the exception "Failed to execute 'toDataURL' on 'HTMLCanvasElement': Tainted canvases may not be exported." Hence why I'm delegating to the background page.


Here is some code to help with some context.

In the content script:

// Can't process image in content script due to CORS which leaves the
// background page as the only real option.
//
// Can't send reference to image element either because it needs to be 
// serializable.
chrome.runtime.sendMessage( { operation: 'get-image-base64', src: img.src },

In the background page, portion of function responsible for processing the get-image-base64message:

var img;

ent = ent.trim();
img = new window.Image();
img.src = /^\/\//.test(ent) ? "http:" + ent : ent;

/* Set up events. */
img.onload = function () { callback(getImageData_(img)); };
img.onerror = function () {
  console.error("Failed to load image: %s", img.src);
};

getImageData_ above simply uses some canvas trickery to retrieve the image data in base64 encoding.

Antony Sargent

unread,
Feb 12, 2015, 5:24:26 PM2/12/15
to Miguel Guedes, Chromium-extensions
The problem may be that the page your content script is running on doesn't have access to the images either because they are not same-origin for the page (eg similar to this question: http://stackoverflow.com/questions/20424279/canvas-todataurl-securityerror). You can check this by comparing the url of the image tag to the url of the page. You might further try opening up the javascript console on that page and try manually running the script commands you want your content script to do, and see if you get the same error from calling toDataURL or not. 

Does your content script have host permissions for the url of the image? If so you might argue that the content script should be allowed to execute toDataURL on the canvas even when the host page cannot. (I don't know off the top of my head if this is supposed to work or not). 

If you create an image tag in the background page pointing at the image source url, what happens with respect to the cache will be the same as for any other kind of resource load ; ie there is no special case here. It depends on the http headers related to caching that the image was served with -  if the image was cacheable then it likely will be in the cache, but there's no special guarantee of that for background pages. 




--
You received this message because you are subscribed to the Google Groups "Chromium-extensions" group.
To unsubscribe from this group and stop receiving emails from it, send an email to chromium-extens...@chromium.org.
To post to this group, send email to chromium-...@chromium.org.
Visit this group at http://groups.google.com/a/chromium.org/group/chromium-extensions/.
To view this discussion on the web visit https://groups.google.com/a/chromium.org/d/msgid/chromium-extensions/d568bd7b-c4ed-4b35-9a6b-a0aa73848649%40chromium.org.
For more options, visit https://groups.google.com/a/chromium.org/d/optout.

Jonathan Lepolt

unread,
Feb 13, 2015, 10:33:37 AM2/13/15
to chromium-...@chromium.org
We actually do something like this with our browser extension... there's no simple solution, but there is a way around the CORS stuff. You basically need to grab the source URL of the image, then make an ajax request to get the image yourself. From there you have easy access to base64 or whatever you want. Here's some code: 
function doGetImage(imgSrc, callback) {
  // Code borrowed from the following Stack Overflow page
  var xhr = new XMLHttpRequest();
  xhr.onreadystatechange = function() {
    if (this.readyState === 4) {
      if (this.status === 200) {
        // this.response is the blob response
        callback(this.response);
      } else {
        console.error('Error sending AJAX request to fetch image. Status: ' + this.status + '. Text: ' + this.statusText);
        callback();
      }
    }
  };
  xhr.onerror = function () {
    console.error('Error sending AJAX request to fetch image: ' + imgSrc);
    callback();
  };
  xhr.open('GET', imgSrc);   // this is a GET request
  xhr.responseType = 'blob'; // Ask for a blob response

  // Finally send the request
  xhr.send();
}

In our case we wanted a blob response, but there are other data types available. Here's our callback function to convert to a dataURL:
function callback(blob) {
  // Can't pass Blob objects around, so convert to dataURL
  var reader = new window.FileReader();
  reader.readAsDataURL(blob);
  reader.onloadend = function () {
    var dataUrl = reader.result;

    // Do something with the dataUrl
  };
}

Good luck
Reply all
Reply to author
Forward
0 new messages