I've got a function in my Angular 1.5 app that resizes a base64-encoded image if it's over a maximum size. This function works great in Chrome, but in Firefox it returns a empty string instead of anything base64-encoded.
I've got it packaged up in an Angular app in Plunker here, but here's the relevant function:
// Image resizing
$scope.resizeImage = function(base64Data, maxWidth, maxHeight) {
img = document.createElement('img');
img.src = base64Data;
height = img.height;
width = img.width;
if (width > maxWidth) {
ratio = maxWidth / width; // get ratio for scaling image
height = height * ratio; // Reset height to match scaled image
width = width * ratio; // Reset width to match scaled image
}
// Check if current height is larger than max
if (height > maxHeight) {
ratio = maxHeight / height; // get ratio for scaling image
width = width * ratio; // Reset width to match scaled image
height = height * ratio; // Reset height to match scaled image
}
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// We set the dimensions at the wanted size.
canvas.width = width;
canvas.height = height;
// We resize the image with the canvas method drawImage();
ctx.drawImage(img, 0, 0, width, height);
var dataURI = canvas.toDataURL();
return dataURI;
}
You may need to wait until the <img> is loaded:
img.onload = function() {
// now your image is ready for use
};
Related
I want to know how we can scale and crop an image in Javascript. I want to scale it down to 300x300px and crop it a little.
Do you have any suggestions ? I have the following code :
function cropImage(imagePath, newX, newY, newWidth, newHeight) {
//create an image object from the path
var img = document.createElement('img');
img.src = "data:image/png;base64,"+imagePath;
//alert(img.width);
//alert(img.height);
//initialize the canvas object
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
//set the canvas size to the new width and height
canvas.width = 300;
canvas.height = 300;
//draw the image
ctx.drawImage(img, newX, 75, 300, 300, 0, 0, 300, 300);
variables.imageCrop = canvas.toDataURL();}
Thank you !
Try it:
And learn more about .drawImage()
function cropImage(imagePath, leftRight, topBottom, newWidth, newHeight) {
const img = document.createElement('img');
img.src = imagePath;
const canvas = document.createElement('canvas');
document.body.appendChild(canvas);
const ctx = canvas.getContext('2d');
img.addEventListener('load', function() {
//Set your canvas size as your choice
//here i just scaled by 10 with original dimension
canvas.width = img.naturalWidth*10;
canvas.height = img.naturalHeight*10;
const cropLeft = leftRight[0];
const cropRight = img.naturalWidth - leftRight[0] - leftRight[1];
const cropTop = topBottom[0];
const cropBottom = img.naturalHeight - topBottom[0] - topBottom[1];
ctx.drawImage(
img,
cropLeft,cropTop,
cropRight, cropBottom,
0,0, //here you can control placement of cropped image from left and top, by default it stays in 0,0 meaning the top left corner of the canvas
newWidth,newHeight //new width and height of cropped image
);
});
}
//Size of this image is 100x100 px
const img = "https://dummyimage.com/100.png/09f/fff";
//here [10,10] meaning crop 10px from left and 10px from right
//here [20,20] meaning crop 20px from top and 20px from bottom
cropImage(img,[10,10],[20,20], 100, 100);
Html canvas decreases the resolution of images and shapes. Is there a way by which we can increase the quality?
Sure:
const width = ..., height = ..., scale = 2;
const canvas = document.querySelector('...')
canvas.style.width = width;
canvas.style.height = height;
canvas.width = width * scale;
canvas.height = height * scale;
Im resizing the image size to make it smaller im taking 20% of the height and 20% of the width. but im getting wrong result is getting me a higher size of an image.
function imageToDataUri(img, width, height) {
var canvas = document.createElement('canvas'),
ctx = canvas.getContext('2d');
canvas.width = width;
canvas.height = height;
ctx.drawImage(img, 0, 0, width, height);
return canvas.toDataURL();
}
imageToAdjust = 'data:image/png;base64,' + window.btoa(e.target.result);
var img = new Image;
img.onload = resizeImage;
img.src = imageToAdjust;
function resizeImage() {
console.log(img.width);
console.log(img.height);
var x = img.width - (0.2 * img.width);
var y = img.height - (0.2 * img.height);
console.log(x);
console.log(y);
var newDataUri = imageToDataUri(this, x, y);
console.log(newDataUri);
var base64 = newDataUri.match(/data:(.+);base64,(.+)/);
console.log('after resizing');
console.log(base64);
var base64Number = Math.round((base64[2].length )*3/4) ;
console.log(base64Number);
}
what im getting through console.logs is for example i have image with size is 5663096 width 4032 and height 3024 then after i take 20% off im getting it width 3225.6 and height 2419.2 which is correct. but after i call imageToDataUri(this, x, y); function the image size will be 12031242 which is double. it should be smaller than 5663096
Im using drawImage to "resize" the image with ;
img.onload = function(){
var width = img.width * 0.16,
height = img.height * 0.16;
canvas.width = width,
canvas.height = height;
ctx.imageSmoothingEnabled = false;
ctx.drawImage(img, 0, 0, width, height);
}
Whenever I use it like this, it shows the image nicely
But whenever i do fixed width and height it shows the init bit blurry
img.onload = function(){
ctx.imageSmoothingEnabled = false;
ctx.drawImage(img, 0, 0, 56, 56);
}
So I want fixed height and width but must show not blurry
Your first version sets the canvas's width and height to be the same dimensions as those of the image, so when you draw the image, no scaling is performed (actually, your img's width and height are scaled down by 16%, or 0.16, to match the value you specify, but it does not scale your image down when drawing into the canvas because the last 2 arguments of drawImage() match the dimensions of the canvas).
img.onload = function(){
var width = img.width * 0.16,
height = img.height * 0.16;
canvas.width = width, // canvas's width === img's width
canvas.height = height; // canvas's heeight === img's height
ctx.imageSmoothingEnabled = false;
ctx.drawImage(img, 0, 0, width, height); // draw img at the same dimensions as those of the canvas => no scaling => no blur
}
Whereas, your second version draws the image at 56x56 size, this does not match the canvas' dimensions, hence the image is scaled down, so it appears a little blurry.
img.onload = function(){
ctx.imageSmoothingEnabled = false;
ctx.drawImage(img, 0, 0, 56, 56); // last 2 arguments tell the browser to draw the image at 56x56 px dimensions
}
I am using JS and a multi select field.
A user can select multiple images from a folder and then each image should be drawn into a canvas. Each image has a predefined canvas and a predefined input field where then the decoded base64 dataurl is placed in.
The multiselect field:
<input id="bild" multiple="" name="bild" type="file">
In my example there are 3 different canvas elements and 3 different dataurl input fields:
$( "input#bild" ).change(function() {
console.log("multiple");
// from an input element
var filesToUpload = this.files;
//console.log(filesToUpload);
if(typeof this.files[0] !== "undefined") {
console.log("multiple-1");
var img = document.createElement("img");
img.src = window.URL.createObjectURL(this.files[0]);
$( img ).load(function() {
console.log("multiple-1-loaded");
canvas = $("#uploading_canvas_image_1").get(0);
var MAX_WIDTH = 550;
var MAX_HEIGHT = 400;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
var dataurl = canvas.toDataURL("image/jpg");
$( "#dataurl_image_1" ).val(dataurl);
});
}
if(typeof this.files[1] !== "undefined") {
console.log("multiple-2");
var img = document.createElement("img");
img.src = window.URL.createObjectURL(this.files[1]);
$( img ).load(function() {
console.log("multiple-2-loaded");
canvas = $("#uploading_canvas_image_2").get(0);
var MAX_WIDTH = 550;
var MAX_HEIGHT = 400;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
var dataurl = canvas.toDataURL("image/jpg");
$( "#dataurl_image_2" ).val(dataurl);
});
}
if(typeof this.files[2] !== "undefined") {
console.log("multiple-3");
var img = document.createElement("img");
img.src = window.URL.createObjectURL(this.files[2]);
$( img ).load(function() {
console.log("multiple-3-loaded");
canvas = $("#uploading_canvas_image_3").get(0);
var MAX_WIDTH = 550;
var MAX_HEIGHT = 400;
var width = img.width;
var height = img.height;
if (width > height) {
if (width > MAX_WIDTH) {
height *= MAX_WIDTH / width;
width = MAX_WIDTH;
}
} else {
if (height > MAX_HEIGHT) {
width *= MAX_HEIGHT / height;
height = MAX_HEIGHT;
}
}
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0, 0, width, height);
var dataurl = canvas.toDataURL("image/jpg");
$( "#dataurl_image_3" ).val(dataurl);
});
}
For each image I am checking if it is really there and not undefined. Then it is drawn into the canvas and the corresponding field for dataurl is populated with the dataurl.
The Problem is:
I do not get any errors.
The behaviour is different with different sets of images but its always the same with the same set. For example: I am marking 3 different images in the folder which I want to upload, but always all 3 canvas show the same image (3rd) one also all 3 dataurls are the same.
Sometimes some canvas are blank.
Sometimes it works
It seems like a general problem, but I havent managed to locate why this happens. My guess is it maybe has something to do with the onload function for the image and that the dataurl is created in the same steps. The dataurl itself is insanly long. I am looking at this atm. Maybe someone here has an idea.
I found the issue. The img was causing these problems. Because I always used the same img, eventhough it is in the if condition block. It seems that the function itself is stronger then the if condition?
I had to create a new img variable for every image selected, which means I needed this for image 1:
var img1 = document.createElement("img");
img1.src = window.URL.createObjectURL(this.files[0]);
$( img1 ).load(function() {
//...
ctx.drawImage(img1, 0, 0, width, height);
});
For image 2:
var img2 = document.createElement("img");
img2.src = window.URL.createObjectURL(this.files[1]);
$( img2 ).load(function() {
//...
ctx.drawImage(img2, 0, 0, width, height);
});
For image 3:
var img3 = document.createElement("img");
img3.src = window.URL.createObjectURL(this.files[2]);
$( img3 ).load(function() {
//...
ctx.drawImage(img3, 0, 0, width, height);
});