21

Using JavaScript, I want to convert an img tag like this:

<img width="11" height="14" src="http://mysite/file.gif" alt="File Icon">

Into one with a dataurl like this:

<img width="11" height="14" src="data:image/gif;base64,R0lGODlhCwAOAMQfAP////7+/vj4+Hh4eHd3d/v7+/Dw8HV1dfLy8ubm5vX19e3t7fr6+nl5edra2nZ2dnx8fMHBwYODg/b29np6eujo6JGRkeHh4eTk5LCwsN3d3dfX13Jycp2dnevr6////yH5BAEAAB8ALAAAAAALAA4AAAVq4NFw1DNAX/o9imAsBtKpxKRd1+YEWUoIiUoiEWEAApIDMLGoRCyWiKThenkwDgeGMiggDLEXQkDoThCKNLpQDgjeAsY7MHgECgx8YR8oHwNHfwADBACGh4EDA4iGAYAEBAcQIg0Dk gcEIQA7" alt="File Icon">

Is this possible?

adam0101
  • 29,096
  • 21
  • 96
  • 174
  • 1
    possible duplicate of [Convert image to base64 with javascript](http://stackoverflow.com/questions/10982712/convert-binary-data-to-base64-with-javascript) – Dalorzo Sep 05 '14 at 16:59
  • Why would you want to do that? – Brad Sep 05 '14 at 16:59
  • 1
    Because jsPDF only seems to support images like that. – adam0101 Sep 05 '14 at 17:00
  • 4
    I don't think it's a duplicate of that answer because he's downloading the binary data from the server and converting it to Base64. I'm trying to convert an absolute url to base64 on the client without downloading it a second time if possible. – adam0101 Sep 05 '14 at 17:05
  • @adam0101 But you have to download it once to convert the data. Then it wont be downloaded again with the base64 string. using base64 images prevents from downloading the images. – Romain Braun Sep 05 '14 at 17:13
  • 1
    @RomainBraun, still, that question and answer converts a string to Base64. I don't have a string to convert, only a url. The `btoa()` function doesn't accept a url. – adam0101 Sep 05 '14 at 17:21

4 Answers4

35

Here's how to get the data url of an image with fetch:

(async function() {
    let blob = await fetch("https://example.com/image.png").then(r => r.blob());
    let dataUrl = await new Promise(resolve => {
      let reader = new FileReader();
      reader.onload = () => resolve(reader.result);
      reader.readAsDataURL(blob);
    });
    // now do something with `dataUrl`
})();
18

First, load the image into a canvas

var canvas = document.createElement("canvas");
context = canvas.getContext('2d');

make_base();

function make_base()
{
  base_image = new Image();
  base_image.src = 'img/base.png';
  base_image.onload = function(){
    context.drawImage(base_image, 100, 100);
  }
}

Make sure to update the context.drawImage(base_image, 100, 100); to values appropriate for your application.

Source: https://stackoverflow.com/a/6011402/3969707

Then convert the canvas to data.

var jpegUrl = canvas.toDataURL("image/jpeg");
var pngUrl = canvas.toDataURL(); // PNG is the default

Source: https://stackoverflow.com/a/15685877/3969707

Community
  • 1
  • 1
Drew Faubion
  • 441
  • 3
  • 12
  • 1
    Thanks! This worked great, but it turns out that if I include html2canvas with jsPDF it takes care of converting the images for me! – adam0101 Sep 05 '14 at 20:51
5

I'd solve this problem with a temporary canvas element with the same size of the image loaded:

function imageToUri(url, callback) {
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    var base_image = new Image();
    base_image.src = url;
    base_image.onload = function() {
        canvas.width = base_image.width;
        canvas.height = base_image.height;

        ctx.drawImage(base_image, 0, 0);
    
        callback(canvas.toDataURL('image/png'));

        canvas.remove();
    }
}

imageToUri('./assets/some_image.png', function(uri) {
    console.log(uri);
});
Ângelo Polotto
  • 8,463
  • 2
  • 36
  • 37
1

This really isn't something you may want to do in JavaScript as it requires the image be parsed in JavaScript which is very slow. You would be loading the image and then putting the output of the function into the img tag, which doesn't save bandwidth, decrease complexity, or improve security.

Your best bet is to do this server-side. I've used this to great success in the past for generating pages which need to have absolutely no linked/referenced external resources. You can, for jsPDF, then use raw JavaScript or jQuery to get the data of an image to pass into the PDF creation process.

This will work everywhere and not rely on resorting to canvas which doesn't have full mobile browser support.

Liam
  • 1,712
  • 1
  • 17
  • 30
  • What if I stored that data on local storage? First I download the image, then I store it in users' local storage. Then users can load that image from their local storage. If the image is already downloaded, then the user can skip the downloading part which might increase the performance. Is this okay? – DxTx Sep 13 '19 at 12:20
  • 1
    Browser caching handles this fairly well so you shouldn't in most applications need to store an image in local storage in most projects. If this is something that you're really looking to do there is another SO question that covers this pretty well. It uses canvas but that's available in all modern web browsers now: - https://stackoverflow.com/questions/19183180/how-to-save-an-image-to-localstorage-and-display-it-on-the-next-page – Liam Jan 15 '20 at 06:50