0

Context

I'm trying to generate a Base64 string of a JPG/PNG/... image after resizing it. For some reason, the resulting Base64 string is that of a plain white image.

Assumption

My assumption of what is causing this, is the following: <canvas width="X" height="Y"></canvas> does not seem to contain innerHTML, where I would expect it to contain <img src="https://static.wixstatic.com/media/6068b5_b0d5df4c3d094694bb5d348eac41128d~mv2.jpg" crossorigin="anonymous"> However, I cannot figure out why ctx.drawImage() does not handle this.

Related issues

Several other people have brought up this issue, but unfortunately, the proposed solutions didn't seem to resolve my issue. See:

  1. Rendering a base64 image, currently comes back as blank
  2. How can I convert an image into Base64 string using JavaScript?
  3. How to display Base64 images in HTML?

Minimal Working Example

async function init(){
    //getDataUrl
    var dataUrl = await getDataUrl("https://static.wixstatic.com/media/6068b5_5888cb03ab9643febc221f3e6788d656~mv2.jpg");
    console.log(dataUrl); //returns string, but white image?
    //Create new image on body tag with dataurl
    addBase64Image(dataUrl);
}

function getImageDimensions(file) {
    return new Promise (function (resolved, rejected) {
        var i = new Image()
        i.onload = function(){
            resolved({w: i.width, h: i.height})
        };
        i.src = file
    })
}

async function getDataUrl(img_url) {
    // Create canvas
    const canvas = document.createElement('canvas');
    const ctx = canvas.getContext('2d');

    var dimensions = await getImageDimensions(img_url);
    console.log(dimensions);

    // Set width and height
    canvas.width = dimensions.w; //img_url.width
    canvas.height = dimensions.h; //img_url.height

    var res = await loadImage(ctx, img_url, dimensions.w, dimensions.h);
    console.log(res);
    res.setAttribute('crossorigin', 'anonymous');
    ctx.drawImage(res, dimensions.w, dimensions.h); //issue: <canvas width="2075" height="3112"></canvas> has no innerHTML e.g. <img src="https://static.wixstatic.com/media/6068b5_b0d5df4c3d094694bb5d348eac41128d~mv2.jpg" crossorigin="anonymous">
    console.log(canvas);
    console.log(ctx);
    
    dataurl = canvas.toDataURL('image/png');
    return dataurl;
}

function loadImage(context, path, dimx, dimy){
    return new Promise(function(resolve, reject){
        var img=new Image();
        img.onload = function() {
            resolve.call(null, img);
        };
        img.src=path;
    });
}

function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
    var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
    return { width: srcWidth*ratio, height: srcHeight*ratio };
}

async function addBase64Image(img_dataurl){
    var dimensions = await getImageDimensions(img_dataurl);
    console.log(dimensions);
    var res = calculateAspectRatioFit(dimensions.w, dimensions.h, 512, 512);
    console.log(res);

    var image = document.createElement("img");
    var imageParent = document.querySelector('body');
    image.id = "user_upload";
    image.width = res.width;
    image.height = res.height; 
    image.src = img_dataurl;           
    imageParent.appendChild(image);
}
body {
    margin: 0px;
}

#user_upload {
  display: block;
  margin-left: auto;
  margin-right: auto;
  border: 2.5px solid;
}
<body onload="init()">
</body>
user1098973
  • 310
  • 1
  • 7

1 Answers1

2

To be able to draw an image hosted on a different domain onto a canvas

a) the webserver needs to permit it and send the appropriate headers

b) you need to set the crossOrigin property of the image to "anonymous"

Obviously you already figured this out yourself, as you already have the line

res.setAttribute('crossorigin', 'anonymous');

in your code.

The problem is that it happens too late. It needs to be set before assigning an URL to the src property of the image.

So simply move the above line inside the loadImage() function, just before the call to

img.src=path;

Here's an example:

async function init() {
  //getDataUrl
  var dataUrl = await getDataUrl("https://static.wixstatic.com/media/6068b5_5888cb03ab9643febc221f3e6788d656~mv2.jpg");
  console.log(dataUrl); //returns string, but white image?
  //Create new image on body tag with dataurl
  addBase64Image(dataUrl);
}

function getImageDimensions(file) {
  return new Promise(function(resolved, rejected) {
    var i = new Image()
    i.onload = function() {
      resolved({
        w: i.width,
        h: i.height
      })
    };
    i.src = file
  })
}

async function getDataUrl(img_url) {
  // Create canvas
  const canvas = document.createElement('canvas');
  const ctx = canvas.getContext('2d');

  var dimensions = await getImageDimensions(img_url);
  console.log(dimensions);

  // Set width and height
  canvas.width = dimensions.w; //img_url.width
  canvas.height = dimensions.h; //img_url.height

  var res = await loadImage(ctx, img_url, dimensions.w, dimensions.h);
  console.log("asd ", res);

  ctx.drawImage(res, 0, 0); //issue: <canvas width="2075" height="3112"></canvas> has no innerHTML e.g. <img src="https://static.wixstatic.com/media/6068b5_b0d5df4c3d094694bb5d348eac41128d~mv2.jpg" crossorigin="anonymous">
  console.log(canvas);
  console.log(ctx);

  dataurl = canvas.toDataURL('image/png');
  return dataurl;
}

function loadImage(context, path, dimx, dimy) {
  return new Promise(function(resolve, reject) {
    var img = new Image();
    img.onload = function() {
      resolve.call(null, img);
    };
    img.setAttribute('crossorigin', 'anonymous');
    img.src = path;

  });
}

function calculateAspectRatioFit(srcWidth, srcHeight, maxWidth, maxHeight) {
  var ratio = Math.min(maxWidth / srcWidth, maxHeight / srcHeight);
  return {
    width: srcWidth * ratio,
    height: srcHeight * ratio
  };
}

async function addBase64Image(img_dataurl) {
  var dimensions = await getImageDimensions(img_dataurl);
  console.log(dimensions);
  var res = calculateAspectRatioFit(dimensions.w, dimensions.h, 512, 512);
  console.log(res);

  var image = document.createElement("img");
  var imageParent = document.querySelector('body');
  image.id = "user_upload";
  image.width = res.width;
  image.height = res.height;
  image.src = img_dataurl;
  imageParent.appendChild(image);
}

init();
body {
  margin: 0px;
}

#user_upload {
  display: block;
  margin-left: auto;
  margin-right: auto;
  border: 2.5px solid;
}
obscure
  • 8,071
  • 2
  • 9
  • 30