Reputation: 334
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.
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.
Several other people have brought up this issue, but unfortunately, the proposed solutions didn't seem to resolve my issue. See:
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>
Upvotes: 0
Views: 644
Reputation: 12891
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;
}
Upvotes: 2