views:

9807

answers:

2

I have a regular HTML page with some images (just regular IMG HTML tags). I'd like to get their content, base64 encoded preferably, without the need to redownload the image (ie. it's already loaded by the browser, so now I want the content).

I'd love to achieve that with Greasemonkey and Firefox.

+2  A: 

You need to use a Canvas, with putImageData and getImageData : https://developer.mozilla.org/En/HTML/Canvas/Pixel_manipulation_with_canvas

Fabien Ménager
+17  A: 

You will need to create a canvas element with the correct dimensions and copy the image data with the drawImage function. Then you can use the toDataURL function to get a data: url that has the base-64 encoded image.

It would be something like this. I've never written a Greasemonkey script, so you might need to adjust the code to run in that environment.

function getBase64Image(img) {
    // Create an empty canvas element
    var canvas = document.createElement("canvas");
    canvas.width = img.width;
    canvas.height = img.height;

    // Copy the image contents to the canvas
    var ctx = canvas.getContext("2d");
    ctx.drawImage(img, 0, 0);

    // Get the data-URL formatted image
    // Firefox supports PNG and JPEG. You could check img.src to guess the
    // original format, but be aware the using "image/jpg" will re-encode the image.
    var dataURL = canvas.toDataURL("image/png");

    return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}

I think getting a JPEG-formatted version requires a recent version of Firefox, so if you want to support that, you'll need to check the compatibility. If the encoding is not supported, it will default to "image/png".

Matthew Crumley
While this seems to be working (except the unescaped / in the return), it does not create the same base64 string as the one I'm getting from PHP when doing base64_encode on the file obtained with file_get_contents function. The images seem very similar/the same, still the Javascripted one is smaller and I'd love them to be exactly the same.One more thing: the input image is a small (594 bytes), 28x30 PNG with transparent background -- if that changes anything.
Detariael
Also http://www.motobit.com/util/base64-decoder-encoder.asp confirms that the Javascript's Base64 encoded string is wrong - if created from the original file, the result is the same as mine from PHP and different from the one from Javascript.
Detariael
Firefox could be using a different compression level which would affect the encoding. Also, I think PNG supports some extra header information like notes, that would be lost, since the canvas only gets the pixel data. If you need it to be exactly the same, you could probably use AJAX to get the file and base64 encode it manually.
Matthew Crumley
But what exactly from AJAX do I need? XMLHttpRequest? But isn't it the exact thing I'm trying to aviod - redownloading the file?
Detariael
Yes, you would download the image with XMLHttpRequest. Hopefully, it would use the cached version of the image, but that would depend on the server and browser configuration, and you would have the request overhead to determine if the file has changed. That's why I didn't suggest that in the first place :-) Unfortunately, as far as I know, it's the only way to get the original file.
Matthew Crumley
And if I decided to go with XMLHttpRequest (or GM's version of it), what would I do with the result? How to convert it to base64 form? Canvas aren't an answer because of the problems above I think. Or maybe there is a way to save a file to the hard drive with JavaScript somehow (but I'm afraid that's not possible due to security reasons)?Will converting my GM script to Fx extension or writing a Fx extension from the scratch give me more power/access to cache files in some way?
Detariael
You would need to use a base64 encoder written in javascript. If found this: http://www.webtoolkit.info/javascript-base64.html by searching google. I've never used it, but I have used some other code from webtoolkit.info. For the second part, I don't know what kind of permissions GM gives you, but I know extensions can read and write files.
Matthew Crumley
But I still miss the part from getting the image with XMLHttpRequest to passing image to some Base64 function. How would I do that, still use the Canvas that has proven unreliable?
Detariael
I think you could pass the xhr.reponseText property to the base64 encoder when the request is done.
Matthew Crumley
I've decided to ditch it for just passing the URL to the PHP script, which would run through caching proxy that the browser will also use.Since your code was doing the thing pretty well, I'm marking it as an answer, even if it's not the ultimate solution.
Detariael