Firefox does not respect 2D canvas transformation for SVG images, however, it does for PNG pictures.
The following code snippet creates two HTML canvases with 2D drawing contexts. On both of them a simple scale transformation is applied, then a 20px sized square PNG image is drawn on the upper one, and an SVG with the same dimensions is drawn on the bottom one.
On my Chromium (v65.0.3325.162) the images are scaled up as expected. However, on Firefox (v58.0.2) the canvas at the bottom (the one with the SVG) is not scaled, unlike the one with PNG source image.
function createPng(xSize, ySize) {
var canvas = document.createElement("canvas");
canvas.width = 20;
canvas.height = 20;
var ctx = canvas.getContext("2d")
ctx.fillStyle = "000000";
ctx.fillRect(0, 0, xSize, ySize);
var img = new Image()
prom = new Promise(function(resolve, reject) {
img.onload = function() {resolve(img)}
img.onerror = function(err) {reject(err)}
})
img.src = canvas.toDataURL("image/png");
return prom
}
function createSvg() {
var img = new Image()
var prom = new Promise(function(resolve, reject) {
img.onload = function() {resolve(img)}
img.onerror = function(err) {reject(err)}
})
img.src = "https://cdn.rawgit.com/AttilaVM/4e0987aae8bc37b2067fbde591088758/raw/95dcffd67b37540d739f4bd5f33f6bead625a90f/test.svg"
return prom
}
var containerPng = document.getElementById("container-png")
var canvasPng = document.createElement("canvas")
canvasPng.width = containerPng.clientWidth;
canvasPng.height = containerPng.clientHeight;
containerPng.appendChild(canvasPng);
var ctxPng = canvasPng.getContext("2d");
createPng(20, 20)
.then(function(img) {
ctxPng.scale(5, 1);
ctxPng.drawImage(img, 0, 0)
})
.catch(function(err) {console.error(err)});
var containerSvg = document.getElementById("container-svg")
var canvasSvg = document.createElement("canvas")
canvasSvg.width = containerSvg.clientWidth;
canvasSvg.height = containerSvg.clientHeight;
containerSvg.appendChild(canvasSvg);
var ctxSvg = canvasSvg.getContext("2d");
createSvg()
.then(function(img) {
ctxSvg.scale(5, 1);
ctxSvg.drawImage(img, 0, 0)
})
.catch(function(err) {console.error(err)});
.container {
position: relative;
margin: 15px 0 0 0;
width: 100%;
height: 20px;
background-color: #aaaaaa
}
.container > canvas {
position: absolute;
top: 0;
left: 0;
}
<div id="container-png" class="container"></div>
<div id="container-svg" class="container"></div>
Screenshots
Chromium:
Firefox:
Question:
What is the best way to write code to draw scaled SVG images on HTML canvas, which gives the same result on both Firefox and Chromium?
It is not in fact a bug. In your original svg, the preserveAspectRatio attribute is missing. This means that the default value is used which is XMidYMid. That will create the problem if the viewBox aspect ratio of the svg does not match to the aspect ratio of the target viewPort (you image). To turn this off, you need to add preserveAspectRatio="none" to your svg. I went to the source of the svg, added the preserveAspectRatio="none" attribute and then did this:
var x = "data:image/svg+xml;base64,"+ btoa(ser.serializeToString(document.querySelector("svg")))
The ser above is an XMLSerializer instance. This will give me a data url which I can use:
"data:image/svg+xml;base64,PHN2ZyB4bWxuczpvc2I9Imh0dHA6Ly93d3cub3BlbnN3YXRjaGJvb2sub3JnL3VyaS8yMDA5L29zYiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmlld0JveD0iMCAwIDI2LjQ1OCAyNi40NTgiIGhlaWdodD0iMjAiIHdpZHRoPSIyMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PGRlZnM+PGxpbmVhckdyYWRpZW50IG9zYjpwYWludD0iZ3JhZGllbnQiIGlkPSJhIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNlMjVlNWUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMxMjkwMzMiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCB5Mj0iMjk1LjQ4MiIgeDI9IjEyLjYxNCIgeTE9IjI3Mi4xNjQiIHgxPSIxMi4xOSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjExMzQ3IDAgMCAxLjExMzQ3IC0xLjUwMSAtMzIuMTk4KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJiIiB4bGluazpocmVmPSIjYSIvPjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2IpIiBkPSJNMCAyNzAuNTQyaDI2LjQ1OFYyOTdIMHoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTI3MC41NDIpIi8+PC9zdmc+"
Next , I created a fiddle and modified these:
function createSvg() {
var img = new Image()
var prom = new Promise(function(resolve, reject) {
img.onload = function() {resolve(img)}
img.onerror = function(err) {reject(err)}
})
img.src = "data:image/svg+xml;base64,PHN2ZyB4bWxuczpvc2I9Imh0dHA6Ly93d3cub3BlbnN3YXRjaGJvb2sub3JnL3VyaS8yMDA5L29zYiIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmlld0JveD0iMCAwIDI2LjQ1OCAyNi40NTgiIGhlaWdodD0iMjAiIHdpZHRoPSIyMCIgcHJlc2VydmVBc3BlY3RSYXRpbz0ibm9uZSI+PGRlZnM+PGxpbmVhckdyYWRpZW50IG9zYjpwYWludD0iZ3JhZGllbnQiIGlkPSJhIj48c3RvcCBvZmZzZXQ9IjAiIHN0b3AtY29sb3I9IiNlMjVlNWUiLz48c3RvcCBvZmZzZXQ9IjEiIHN0b3AtY29sb3I9IiMxMjkwMzMiLz48L2xpbmVhckdyYWRpZW50PjxsaW5lYXJHcmFkaWVudCB5Mj0iMjk1LjQ4MiIgeDI9IjEyLjYxNCIgeTE9IjI3Mi4xNjQiIHgxPSIxMi4xOSIgZ3JhZGllbnRUcmFuc2Zvcm09Im1hdHJpeCgxLjExMzQ3IDAgMCAxLjExMzQ3IC0xLjUwMSAtMzIuMTk4KSIgZ3JhZGllbnRVbml0cz0idXNlclNwYWNlT25Vc2UiIGlkPSJiIiB4bGluazpocmVmPSIjYSIvPjwvZGVmcz48cGF0aCBmaWxsPSJ1cmwoI2IpIiBkPSJNMCAyNzAuNTQyaDI2LjQ1OFYyOTdIMHoiIHRyYW5zZm9ybT0idHJhbnNsYXRlKDAgLTI3MC41NDIpIi8+PC9zdmc+";
return prom
}
See the fiddle here:
https://fiddle.jshell.net/ibowankenobi/4ntq2qLz/1/
Seems like it solved the problem in the firefox browser I was testing.
Related
l believe to have a logic error in the way of which my logic is meant to find the previous coordinates of my canvas object, a moving image, and delete the frame drawn before it so that it does not duplicated the image every time it is drawn onto the canvas.
There is a reproducible demo below and l added comments where l believe the problem occurs.
var canvas = document.getElementById("c");
var ctx = canvas.getContext("2d");
var the_background = document.getElementById("the_background");
var imgTag = new Image();
var X_POS = canvas.width;
var Y_POS = 0;
imgTag.src = "http://i.stack.imgur.com/Rk0DW.png"; // load image
function animate() {
/* Error resides from here */
var coords = {};
coords.x = Math.floor(this.X_POS - imgTag);
coords.y = Math.floor(this.Y_POS - imgTag);
ctx.clearRect(coords.x, coords.y, X_POS, Y_POS);
/* To here */
ctx.drawImage(imgTag, X_POS, Y_POS);
X_POS -= 5;
if (X_POS > 200) requestAnimationFrame(animate)
}
window.onload = function() {
ctx.drawImage(the_background, 0, 0, canvas.width, canvas.height);
animate();
}
html,
body {
width: 100%;
height: 100%;
margin: 0px;
border: 0;
overflow: hidden;
display: block;
}
<html>
<canvas id="c" width="600" height="400"></canvas>
<img style="display: none;" id="the_button" src="https://i.imgur.com/wO7Wc2w.png" />
<img style="display: none;" id="the_background" src="https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg" />
</html>
It seems logical to only clear the subset of the canvas that's changing, but the normal approach is to clear and redraw the entire canvas per frame. After the car moves, the background that's cleared underneath it needs to be filled in, and trying to redraw only that subset will lead to visual artifacts and general fussiness. Clearing small portions of the screen is a premature optimization.
Canvases can't keep track of much of anything other than pixels, so an animation is more like a flipbook of stationary frames and less like a cardboard cutout animation, where the same pieces of cardboard move along and overlap one another.
Math.floor(this.X_POS - imgTag) looks wrong -- imgTag is an image object, which doesn't make sense to subtract from a number. You may have meant to grab the x property from this.
Use image.onload to ensure the image is actually loaded before running the loop. It's a bit odd to use image tags in the DOM just to load images for a canvas. I'd do that programmatically from JS which saves some typing and makes it easier to manage the data.
const loadImg = url => new Promise((resolve, reject) => {
const img = new Image();
img.onerror = reject;
img.onload = () => resolve(img);
img.src = url;
});
const images = [
"https://img.freepik.com/free-photo/hand-painted-watercolor-background-with-sky-clouds-shape_24972-1095.jpg?size=626&ext=jpg",
"http://i.stack.imgur.com/Rk0DW.png",
];
Promise
.all(images.map(loadImg))
.then(([backgroundImg, carImg]) => {
const canvas = document.getElementById("canvas");
const ctx = canvas.getContext("2d");
const car = {x: canvas.width, y: 0};
(function update() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.drawImage(
backgroundImg, 0, 0, canvas.width, canvas.height
);
ctx.drawImage(
carImg, car.x, car.y, carImg.width, carImg.height
);
car.x -= 5;
if (car.x > 200) {
requestAnimationFrame(update);
}
})();
})
.catch(err => console.error(err))
;
<canvas id="canvas" width="600" height="400"></canvas>
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:
Rendering a base64 image, currently comes back as blank
How can I convert an image into Base64 string using JavaScript?
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>
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;
}
This is my first time using HTML canvas. I have been given a working camera that returns images as a base64 string. I am trying to pass this string to a new function that handles the image resizing(the actual dimensions aren't important right now as I am just testing the resizing).
Right now I am getting a blank image from my generateThumbnail function. Below I have attached an image of the output in the application, as well as an image of the console output.
For the first attached image, you will see 2 photos. The photo on the left is the original which is working correctly (it is all black because my webcam is covered). The photo on the right is the blank output when I attempt to resize.
generateThumbnail(imageData) {
let canvas = document.createElement("canvas");
let ctx = canvas.getContext("2d");
let img = new Image();
img.onload = () => {
ctx.drawImage(img, 0, 0, 300, 300);
}
img.src = imageData;
let dataUrl = canvas.toDataURL("image/png");
console.log(imageData);
console.log(dataUrl);
return dataUrl;
}
image of taken photos
image of console output from thumbnail base64
Although your code is not working on the embedded fiddle, I think your problem is because the image has not loaded yet as you're returning dataUrl as soon as you execute your method.
dataUrl
should be returning inside img.onload method , maybe something like this will work?
** EDIT **
Make sure you set width and height of your canvas as well.
const generateThumbnail = (imageData) => {
let canvas = document.createElement("canvas");
canvas.width = 300;
canvas.height = 300;
document.querySelector(".canvas").appendChild(canvas);
let ctx = canvas.getContext("2d");
let img = new Image();
img.onload = () => {
ctx.drawImage(img, 0 , 0, 300, 300);
console.log(imageData);
console.log(dataUrl);
return dataUrl;
}
img.src = imageData;
let dataUrl = canvas.toDataURL("image/png");
document.querySelector(".image").appendChild(img);
}
window.onload = () => {
generateThumbnail(window.image_base64);
}
.canvas, .image {
position: absolute;
top: 0;
left: 0;
width: 300px;
height: 300px;
color: white;
}
.image { border: solid 1px white; }
.canvas {
left: 310px;
top: 0;
width: 300px;
height: 300px;
}
body {
background: purple;
}
<div class="image"></div>
<div class="canvas"></div>
<script>
window.image_base64 = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAASwAAAEsCAMAAABOo35HAAAFU2lUWHRYTUw6Y29tLmFkb2JlLnhtcAAAAAAAPD94cGFja2V0IGJlZ2luPSLvu78iIGlkPSJXNU0wTXBDZWhpSHpyZVN6TlRjemtjOWQiPz4KPHg6eG1wbWV0YSB4bWxuczp4PSJhZG9iZTpuczptZXRhLyIgeDp4bXB0az0iWE1QIENvcmUgNS40LjAiPgogPHJkZjpSREYgeG1sbnM6cmRmPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5LzAyLzIyLXJkZi1zeW50YXgtbnMjIj4KICA8cmRmOkRlc2NyaXB0aW9uIHJkZjphYm91dD0iIgogICAgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIgogICAgeG1sbnM6ZGM9Imh0dHA6Ly9wdXJsLm9yZy9kYy9lbGVtZW50cy8xLjEvIgogICAgeG1sbnM6cGhvdG9zaG9wPSJodHRwOi8vbnMuYWRvYmUuY29tL3Bob3Rvc2hvcC8xLjAvIgogICAgeG1sbnM6eG1wTU09Imh0dHA6Ly9ucy5hZG9iZS5jb20veGFwLzEuMC9tbS8iCiAgICB4bWxuczpzdEV2dD0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlRXZlbnQjIgogICB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE4IChNYWNpbnRvc2gpIgogICB4bXA6Q3JlYXRlRGF0ZT0iMjAxOC0xMC0yNFQxNjo0NTowNiswMTowMCIKICAgeG1wOk1vZGlmeURhdGU9IjIwMTgtMTAtMjRUMTY6NTE6MTUrMDE6MDAiCiAgIHhtcDpNZXRhZGF0YURhdGU9IjIwMTgtMTAtMjRUMTY6NTE6MTUrMDE6MDAiCiAgIGRjOmZvcm1hdD0iaW1hZ2UvcG5nIgogICBwaG90b3Nob3A6Q29sb3JNb2RlPSIyIgogICBwaG90b3Nob3A6SUNDUHJvZmlsZT0ic1JHQiBJRUM2MTk2Ni0yLjEiCiAgIHhtcE1NOkluc3RhbmNlSUQ9InhtcC5paWQ6N2Q3MTU5YWYtYzM3Ni00YWVhLWFkNTYtYzNlYWFiZTUwZWU2IgogICB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjdkNzE1OWFmLWMzNzYtNGFlYS1hZDU2LWMzZWFhYmU1MGVlNiIKICAgeG1wTU06T3JpZ2luYWxEb2N1bWVudElEPSJ4bXAuZGlkOjdkNzE1OWFmLWMzNzYtNGFlYS1hZDU2LWMzZWFhYmU1MGVlNiI+CiAgIDx4bXBNTTpIaXN0b3J5PgogICAgPHJkZjpTZXE+CiAgICAgPHJkZjpsaQogICAgICBzdEV2dDphY3Rpb249ImNyZWF0ZWQiCiAgICAgIHN0RXZ0Omluc3RhbmNlSUQ9InhtcC5paWQ6N2Q3MTU5YWYtYzM3Ni00YWVhLWFkNTYtYzNlYWFiZTUwZWU2IgogICAgICBzdEV2dDp3aGVuPSIyMDE4LTEwLTI0VDE2OjQ1OjA2KzAxOjAwIgogICAgICBzdEV2dDpzb2Z0d2FyZUFnZW50PSJBZG9iZSBQaG90b3Nob3AgQ0MgMjAxOCAoTWFjaW50b3NoKSIvPgogICAgPC9yZGY6U2VxPgogICA8L3htcE1NOkhpc3Rvcnk+CiAgPC9yZGY6RGVzY3JpcHRpb24+CiA8L3JkZjpSREY+CjwveDp4bXBtZXRhPgo8P3hwYWNrZXQgZW5kPSJyIj8+woa73QAAAQVQTFRF////QoX0dXV16kM1+7wFNKhTcnJycHBwbW1t9/z4Mn7zyebQH6NGSbBk+7kAa2trxtn7fHx8mZmZOoH0sLCw6TQi6j4v6TkpnLz4L3zz6Tsr5eXl8/PzgoKCxsbG9/r/0dHRZZr20NDQjY2N6S0Z6+vro6Ojv7+/2+f9856Y60g6/fDvQK1cioqK+MnG2tra6PD+lbf4/OjmVZH1//zz97+7ha339bGss8v6+dHOvdL7Sor04uv99ri0+9za8pSO/vHS/NNwdqP273Vs7FlOqsP57mlf//bi8H52/um58YyF/eCf/u/N61FEG3Xz/d6X/MlH/M1Ya532/MUw/dZ+/duN9KahgpOxnQAAAAlwSFlzAAALEwAACxMBAJqcGAAAEHlJREFUeJztnPlzG8eVgL8ZDAYHRYICQBEUQYGiRJGSrIuUbF12dFiWz83m2P0jU1uVcuLKOsnapTi+Uo4Uybaiy5Yo66JEEuIlgjgI7A/dMxjMDCjbFZPc2vf9YHPevOl+87rndffrhkAQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQBEEQhJ8CI0zYfWRuKn2J48uR1L3ra23RBibgrMLcrpVrJIoAaUr0lnKX19wqlwQApfUzoAWfswrlHbcrxRZRInHg0uzaGdRat1UAuPNsnepflYKRMYJkkqPrZE+iMxqNRqMd61S9n4j34vijUliPL9Wiw7G5NTKohahZA4hU16Py1Tge2qua3ev4Oti0YXtWbbHZq9J0lSBNtMuVlWqbFtfWNDZcz7KcP3KTrizRW1rpGXi6meXu+uCEE+4rg5P+h/+/4Tgr5wyLaXtr9HOYhbsAhR0lPY3oml4H8zYkR5M6NCVPdPtuHTzTZxhGZrywDmZtsJil6O5zfJULuTs6bmS2r7lNsDGddUaPg5kTbRTOrUe3YkM667jzDRrr5JO2bDBnmcANZ35w4O56mrLxsXDXqQn78npa8n8AEwrKWemR2fU1ZeNjQp/6a7S4uqaAwclrykuNH1vEGOWrz1E5DzN/X1WjkCD7cUCasJYB7ECK5nvU+RNgkdBf4cyPefzY7MD9+1Ytctq+287485b9+w8A652lP7ZROZkoXkozZQz2B/0V5JXcrKqz8tH3M/JAabp/6akZe9BeZbhah81XPJK8PZ+GWuW+R2Zw5koRIPfo+9XsZW+jstCYAchYyaHJL0NU3oh9CEsAJFl660FI/zpeflhB9e7c7srHHJoEOPI7QnvWy93XnDq77hz+23NtHJpdipUAjPhCOu59dbIAsQeQ75gsA7HcDedWvmOy3GhgGLFI1wRwYBmoUtBTrHbz0VV4KeJly87XjgVU3u6yvHRZPw+ojCY9qaFM8hw5tZaAsHnW/p4tnjp7Xg1W2cK2gZRtusRiWe/NeCwWSw3BNjOu7vc7d7J23HnGTg0A2VQ8Hk9HthuLAOnUKp00lLF911oyhaXZ+eKpW606v/5wqeW6yoNT37aqHL234CmmVFvaxDOAaJWQFM3u8iNvpaWF4vh3q9iYn1pcrjcv6/Va4an3sl6nY3bXTGUFAGtWyYc7ZqsrrlKltHOGgenqimEbxy+XABL2rL+m7nADlN6xqTthN08/aoauw4U/L4WoJE/8d/Pi0GS7vE9iicBnePbLkBH7V79pUwL9U9QAsGNQbiiPd0bd7IkJ2CMTC+4Dyq/xirqKGjHK9RrQmWOiirXJ0o5PpWYD5oZacOR3ANx2q8x2wpyhh4evDjSd1fRVEnAiF0ufnLrgqORcX6VLqTm9p9SWN79w7vcmYS76GIBL+8NiJZB/aNUA7MaWlSTVxWqpBizYIze8WgsLQNSo0IlyY/8UAJ1mpKtzqRz/xq6wUBppABjnLhUBEmOBgSh0S1G1OHunlHcyjaPf9CxuanRc1O+RPfS+Vjx9UXsnyXgjVk5s+q1bxkEd5rsTjq9yW7/NMXnkk+Y3FuxZR5w8ZJbxu1fHIj0XpwEyWSN8IN53owZYxuAzFdb707cqAJ2bdMQxtaJlbrsJ9Bv3ATbPAUT7JvTd7GIFrBpYm8ip8Jo5GKisTS4egNdVgO1954hW3usE3p37tcQN7b8+7BilRV2/8NWQ3K63j46fcIN9MMDv0TX0/myv0n6zR12/HuqrkbhpmmZsX94vsh0n6RAeT3tU2BU3TdOM72pK8nqIsNOcU+YlT/4QZx3bqez2mHnsHf0ue9T1YcdXp1yVw79wvPWGEmQCSbTC9kxbZynXbNnSHAB/1qva55UQX+XV+JduEQ6lTNM04yNeZ3n9AsNKo2XUHLC1s0xnLPpBSePOeQCy7zdFnz3QYWvqJQB6tfzsBVfl7789q6NXDICDenJ1ohnk79YH21aqFxqjn7mSvxzIAMzHQ7SXbYAtrVHwdg6g8sQrS970XhnLQDTZ4o14zflrVCVJM8EUaTLTSrNn6Rbt8bWoIz6GO8Hq8pV5yiseD02inUuG96yzqmM1Fffv7I04H2bAeFKmaZp2QBzziFXfa7k9FPf0vCYDtupZJbV7WgxuC3ZFWxkDVD4n2gDI7PctN3RzmLO4Q6l/7nDhbFN88iEACV8S7Wabkw1KzVnB7n3p1Ud33Pa/FVRXE6KAOG8BNU+Qah3GrDpQCSxFDRXmzLu71Wf9l0C5kz5Szo2xf84ANKZ8D1w91AvQGADqSwDJd/yFLqv/nQdqc8238nD3CGHoXqw/qzev33bmXJl0Nh2yc1ADLDMgrpoAmaag1Z8lwOpuWRQB1FX/M/VM7PknVQplAFIQ0xPqwPxmpgow8wHwrpIs+1W0g02grOwc9KtYfoGybw4gcxbgyKuXKeoQmT04+PjapXCTjUhAFPOZZbX0rPyTGpibAk/d77KU1XfUF/xcZw3cBmAI6qp1DgRUVlRLblc9J7RUPcMygVm1H9ntVwl2B4DtJoBVZmz3nokv1XyUTJrxP30Rpj4MoAJfC7caAM0Mi9FSWyMOsDlYXEJblhpS18G5Qyv6q3kIaii0gj2g7HbvsjYzuOOfdP+rPv9SzK9xL7R65Z6VJ2cfFG/oXpXZvn9o9A/h1qpqQl67ilt1kGgZgoEWKBoAFnf1V3upe7ZNEQCc/FaFzKerKQVol/FrAGEDfns6IgDT03qgzzQOpH/z5JvVn4mFzIf6H9eCQgfVzdp+ZCZc1028Y9WNsIpaXpZSsA+AWj2gEwskEM8HdFSzVYHlNEBiwq8R0h2AOyveq/S+vv9pu4AGPTKXo8Ebq/lKx++2OWMT0NOOid52SsDo1yrCHLkLd+oAM1cCSjFV2RwsLjWLb0EvfSq4B3j2+FUCgwIA2WbbZNLpgQ/arJ4dVNwOfOL6RrsFezUGOinYSr0B6m305KF471zbugsZ9bHa87ijbT2QeLPdyO98foEX14N8BEiVAIplv8pAqAVuh+hNHxycajP8NbkPziu2cMAAJ6IFMUpAIySzt1gD5ayidvTk10fbFFIwr6uOdew6MNMDQDTlV5uaBrBs4OUkwNJf/Sp6vvcecE89/w+/Snizf6ZrGzm4O3z882EBtWBMe9CA0B4HwP0RCxp9AXm/MxrC5Zd0e4dm0QGy8+oN7H8CXO3LADy+ONaq9ZKaRFWncKO3vwnP/7UpLqlh2B9Ou6+F26AH7fgfvt82hQHQGRAnGmF1upQNqN3sD4hbvpAT7tGQ7kABhZxzFmLcEekEQ0+L3mtK2vsmAKdVguFXh70q/+HkbQA4qUrtazneeyjZJuuw15cCAmDvO1vO7g19bZUq2OaTqlyEbknTNM2YL0BtNk3TjPu8tSumsw7q8pnu+8VPE9tbV4mFo/l53RBpd810Skc5zwJ279kraiysqxyCHjX+XPAMiD//o97neQuAj1Upkze6myrnJtu1+lX1Wncee5bvY31/m7l23V0f5XcM7HAWwWq2Oel77RiANdymCiBi48y6XYa+8x3THG1usSTHm019sNtwj9gYHi/u0V3rNdfyPVu1yHGgm/x7y1H5d0fkdDen6MwhPWspvOjWFpL8c3IM/+kU+HJkSyQSifTozpXfbNt2aoe+udk2TdM2W7ylMnspvfYI61molOEOryjmJP+c1dP0+DOnSWuPlmq/jO/bsTR8/Pr8Ss0dhhK3m8/3qfBUmq8cTj+EV3Jjn6tulzn6J63izoserbxxC87veuE93UDJ/AX1x/iKmuGXKpVUZg5GZ5+6uwfB3Z1RbeHS48HTTMEr+y+rk+glw5wGSD2t1euVpW7VfXPPVqBuNXrdQ+nD/berQDQ2oa4NIBLzzde3Lq9A/dnWeVcy4qxn7eY6crxlZ0t/Zx5JYv/nnqse51amUSTbqfc9yVg5Z1Q/dck1I7kESXcVkTz9rnPjzOdOnWm7Mnrd9mz1hOzuvP4PZ0ae7VyIJJl31tIvfADQP6PmzSm9yNj1nUq5bzOv6Ot6DbA6OnRWwQSinf5ZfnoWwBp89gAgbzam3By8Z9F96MYquytpVma9169fDNVN72zmMd/4JGwnjORr/+X+XTDn21UZthX26ldh+VztK7Y9Uc6KOjO3gSdVAMtMmpCO3VQdO5p15lHhzso/qamnhstF6o1SvQZ0L9awfNmIc80A1UrIdHV3r3dvWO9ftKq8bbVuSLdEMM0ZX5WZMy+2iVng7lF4N8LdQaY/pUKLZ1K7ywzgiWGhMQvyA7HWR+LbGIl5Y5biduZZIrh2Sid2fRp01vR4fq5l5OqNHZ5ozQfeHBv07Rcnz//eV8ydI0veUnIvfLiyyo70rWZo1ba5MZKF/LM60BFv/nJmxoi2rGCtjqxneh4as2C+q6da9zxmj9wkO1vHtH3pscXCzmh8pctjUDq1P9l12V8gwN1v98Vi7mwi27vb+sifO3048W/3o+6bJqNv9r0XKObeKCtOAyVq+z5ieBIguwhEty9almXRHLq/e/tJIumYl0kkhz5sltSRf2pGOqLeEy79kZWIoV/cinT0bfEmoLuIROKRYKyYnxmNoLelLSuy6Q4YlTrm1pCd1IPJ8qW0sidB8dXVfp55bHPkYtWsg9k4dTV8q/NUynpX7+m83LgQqlLYVZygBCRGPgUOXQbnVI/6AOstvelI14Us1KFn24xv4ZPePBc4WLQtdcMEaOStemuufhAwy+FnPA58FTWA+kjl2X0gu1DFGgzfdi4kJvfUTf6Zi18Ove9hLFanbkVnVjlbdjjXoB6h2u54FlBIpOvXdW0vfgHPOQL1Shl7ruOzVTS85DMLNate/YEnX/qzCzXLOZ6VXqwRHfxhBawFhRMq0q+3HV6GU6ZppgJLxjXn5CGfYDRpGIaR+eW6WAMwnA0sh7Ix0zTtNlspa0b3WCDH0KXObYaMv2vD0BP8qfP8kxpYm9b3hPK58WTGMFp3Sg5mQlIRa0d2c9w0Y76utStmmmZqqM2+09pw8pOJUtGf8taTpKF1+sV9ulSBxrT3XA0j31WBrtttHlkj9Gmn8YNNkf7NVcjRizVCnUra7O1bamWwrd2JtTXikPOrocShb3NPB752D7MlRgLJ5jVDLaRJ9VSiJTLLS1P1GkDnuvyi3ot7GsvIJJN9zWPLP+Lo9L8OvTKMxVOpVDymz2bFD9DuYMFakUo7WaAilNzU+I/7AcO/ivyDCkDVWfEAFiNX8P27DmvOZG+6HIzk6ZXAMZa15OlQyzoasJPdt2C9ncWkHS/70xzp3TdDddeMmdFI2Wi6y4p0FhdWUV9LzrX+2xuZ5Jn1tgjYti9u27Zt27G45wjvRliCFfq2vp+aIwW7I6Xv81On9WIjOAvg5NfkeH6OQxAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRAEQRCEn4D/BXJsajf86qhZAAAAAElFTkSuQmCC";
</script>
I am currently trying to draw an image to canvas, I have this so far:
"use strict";
var debugging = true;
var canvas = document.getElementById('astoniaCanvas');
var ctx = canvas.getContext('2d');
function loadUI() {
var topOverlay = new Image();
topOverlay.src = "/images/00000999.png";
topOverlay.onload = function() {
ctx.drawImage(topOverlay, 0, 0, canvas.width, 10);
}
var bottomOverlay = new Image();
bottomOverlay.src = "/images/00000998.png";
if (debugging) {
console.log('Drawing');
}
}
loadUI();
That works fine, but the image loads and looks like this:
When it should look like this:
The dimensions of the good looking picture are 800x40.
If I remove the
canvas {
width: 100%;
height: 100%;
}
the image goes back to looking normal, how can I scale my canvas?
Any information would be great thanks.
You arent accounting for height. Canvas can be confusing when it comes to height/width vs clientHeight/clientWidth
When you create a canvas the css width and height has no bearing on the number of pixels the internal canvas contains. Unless specifically set a canvas comes with a width height of 300x150.
A trick I have used in the past is to use the clientWidth and a scale to set everything
"use strict";
var debugging = true;
var canvas = document.getElementById('astoniaCanvas');
var ctx = canvas.getContext('2d');
function loadUI() {
var topOverlay = new Image();
topOverlay.onload = function() {
// use a scale between the image width and the canvas clientWidth
var scale = topOverlay.width / canvas.clientWidth;
var newWidth = canvas.clientWidth;
var newHeight = topOverlay.height * scale;
// resize canvas based on clientWidth
canvas.width = newWidth;
canvas.height = newHeight;
ctx.drawImage(topOverlay, 0, 0, newWidth, newHeight);
}
topOverlay.src = "http://i.stack.imgur.com/AJnjh.png";
// var bottomOverlay = new Image();
// bottomOverlay.src = "/images/00000998.png";
if (debugging) {
console.log('Drawing');
}
}
loadUI()
<canvas id="astoniaCanvas" style="width: 100%"></canvas>
I googled enough examples and found solution how to resize images:
function imageToDataUri(img, width, height) {
// create an off-screen canvas
var canvas = document.createElement('canvas'),ctx = canvas.getContext('2d');
// set its dimension to target size
canvas.width = width;
canvas.height = height;
// draw source image into the off-screen canvas:
ctx.drawImage(img, 0, 0, width, height);
// encode image to data-uri with base64 version of compressed image
return canvas.toDataURL();
}
function resizeImage() {
var newDataUri = imageToDataUri(this, 10, 10); // resize to 10x10
return newDataUri;
}
and this is my problem:
I have list of objects where each Item has based 64 image string: group.mAvatarImgBase64Str. That string is greater then 10x10 and I need replace it with new String.
So far I did:
if (group.mAvatarImgBase64Str !== 'none') {
var img = new Image();
img.onload = resizeImage;
img.src = group.mAvatarImgBase64Str;
// group.mAvatarImgBase64Str = ??
}
If I'll print out new value in resizeImage method - It resized properly but:
How do I add new String back to group.mAvatarImgBase64Str?
onload task is async and I need something like:
group.mAvatarImgBase64Str = resize(group.mAvatarImgBase64Str, 10, 10);
Thanks,
You should be able to do it this way:
if (group.mAvatarImgBase64Str !== 'none') {
(function(group) {
var img = new Image();
img.onload = function() {
group.mAvatarImgBase64Str = resizeImage.call(this);
}
img.src = group.mAvatarImgBase64Str;
})(group);
}
Additional IIFE is needed in case if you use for loop to iterate over array of object. If you use forEach loop, it's not needed.