resize an image using canvas - javascript

Hi want to resize an image using canvas but can't get it to work...
I want the image to be 100px * 100px, is there any way to solve this?
I have tried googleing and trying but can't get it to work...
I also tried changing the img size in css but this doesn't help either, please help me!
function getBase64Image(img) {
// Create an empty canvas element
var canvas = document.createElement("canvas");
var ctx = canvas.getContext("2d");
canvas.width = img.width;
canvas.height = img.height;
// Copy the image contents to the canvas
ctx.drawImage(img, 0, 0);
// Get the data-URL formatted image
// Firefox supports PNG and JPEG. You could check img.src to guess the
// original format, but be aware the using "image/jpg" will re-encode the image.
var dataURL = canvas.toDataURL("image/png");
return dataURL.replace(/^data:image\/(png|jpg);base64,/, "");
}
I also realized that I need to rotate it how can I do this?

You have to get a ratio of the width and apply it to the height.
var ratio = 100 / img.width; // 100 for desired width in px
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
ctx.drawImage(img, 0,0, canvas.width, canvas.height);
typed on phone so forgive small mistakes.

Related

Blank image after resizing in canvas

I'm trying to resize an image using the canvas method. I am then getting the ArrayBuffer and using that to upload the new image. Here's my resize method.
function resizeImage(img) {
var perferedWidth = 160;
var ratio = perferedWidth / img.width;
var $canvas = $("#canvasTest");
var canvas = $("#canvasTest")[0];
canvas.width = img.width * ratio;
canvas.height = img.height * ratio;
var ctx = canvas.getContext("2d");
ctx.drawImage(img, 0,0,canvas.width, canvas.height);
var imageData = ctx.getImageData(0, 0, canvas.width, canvas.height).data.buffer;
return imageData;
}
The problem is once the image gets uploaded, it's just a blank image. I am not doing something correct as the imageData is not giving me a valid buffer. I know it's not valid because when I convert the imageData to a base64 string, it's not a valid base64 encoded image (image doesn't show up when I set its src to it).
I also know that the drawImage method is working, as I have temporarily created a canvas in the DOM and it is correctly drawing the image to that canvas.
What am I doing wrong? Thanks!

HTML flexible canvas scale

I am making a website which will load some blueprint images on a canvas.
but the images are vary in height and width.i Would like to make the canvas scaling equal to the uploaded image scale. How do i code to make the canvas width and height changeble respective to uploaded image.
This done in html5
If I understand you correctly, you want to load images with various dimensions. According to the dimension, set the width / height of the canvas and draw the image?
In that case you could add an eventListener to the image. Once it's loaded, get the width and height. Use those to set the dimensions of the canvas. After that, draw the image on the canvas.
var image = new Image();
image.addEventListener('load', function(e) {
var width = image.width;
var height = image.height;
var canvas = document.querySelector('canvas');
canvas.width = width;
canvas.height = height;
canvas.getContext('2d').drawImage(image, 0, 0, width, height);
});
image.src = 'https://upload.wikimedia.org/wikipedia/commons/c/c4/PM5544_with_non-PAL_signals.png';
<canvas></canvas>
Fiddle
var canvas = document.getElementById('myCanvas');
var ctx = canvas.getContext('2d');
var imageObj = new Image();
imageObj.src = 'images/e1.jpg';
canvas.width = imageObj.naturalWidth;
canvas.height = imageObj.naturalHeight;
this also works

Create Canvas element with image and append to parent

I need to create Canvas element with image and need to append to parent for this i have done this
<html>
<head>
<script>
window.onload = function() {
var canvas = document.createElement('canvas');
var context = canvas.getContext("2d");
canvas.id = "canvas_id";
canvas.setAttribute("class" ,"canvas");
canvas.height = "400";
canvas.width = "800";
var image = new Image();
image.src = "http://localhost/tile.png";
image.onload = function(){
context.drawImage(image, canvas.width, canvas.height);
}
document.body.appendChild(canvas);
}
</script>
</head>
<body>
</body>
</html>
it give blank canvas
can somebody guide me ?
You are using drawImage() the wrong way. Instead of drawing the image at (0,0) you are drawing it just outside the canvas area as width and height is where position normally goes.
The valid signatures are:
context.drawImage(image, dx, dy)
context.drawImage(image, dx, dy, dw, dh)
context.drawImage(image, sx, sy, sw, sh, dx, dy, dw, dh)
Where dx and dy are delta position (relative to origin, normally (0,0) when untranslated). Without width and height specified drawImage() will by default use the image's natural width and height.
The second version allows to override the default size, and the third will allow you to draw from one region to another.
Source
Corrected example:
window.onload = function() {
var canvas = document.createElement('canvas');
var context = canvas.getContext("2d");
canvas.id = "canvas_id";
canvas.className = "canvas"; // should be className
canvas.height = 400; // should be numbers
canvas.width = 800;
var image = new Image();
image.onload = function() {
// or set canvas size = image, here: (this = currently loaded image)
// canvas.width = this.width;
// canvas.height = this.height;
context.drawImage(this, 0, 0); // draw at (0,0), size = image size
// or, if you want to fill the canvas independent on image size:
// context.drawImage(this, 0, 0, canvas.width, canvas.height);
}
// set src last (recommend to use relative paths where possible)
image.src = "http://lorempixel.com/output/fashion-q-c-800-400-7.jpg";
document.body.appendChild(canvas);
}
That being said, if you only need the image appended there is no need to go via canvas. Just add the image to DOM directly (I assume this is not you want, but just in case..):
var image = new Image();
image.src = "tile.png";
document.body.appendChild(image);
This is my take on it... You need to indicate the coordinates where you want to start drawing (i.e. 0, 0) and - optionally - you can specify how big (wide, height) the canvas is to be.
In my case, I make the canvas to be as big as the image (instead of an arbitrary 400x800) you may need to update that your suit your requirements.
I added some css to show how big the canvas is in relation to the image. You can update/remove that as well depending on your needs.
UPDATED
It uses an hidden image as the source.
I hope this will work for you.
window.onload = function() {
var canvas = document.createElement('canvas');
var ctx = canvas.getContext("2d");
canvas.id = 'canvas_id';
canvas.setAttribute("class", "canvas");
var image = new Image();
image.src = 'http://placekitten.com/g/200/300';
canvas.width = image.width;
canvas.height = image.height;
ctx.drawImage(image, 0, 0, image.width, image.height);
document.body.appendChild(canvas);
}
.canvas {
border: solid red 1px;
}
<html>
<body>
</body>
</html>

Resize a Base-64 image in JavaScript without using canvas

I need a way to resize pictures in JavaScript without using an HTML element.
My mobile HTML app capture photos and then converts them into base64 strings. Finally I want to resize them before they are sent to the API.
I'm looking for a different and more suitable way to resize than using a canvas element, is there a way?
A way to avoid the main HTML to be affected is to create an off-screen canvas that is kept out of the DOM-tree.
This will provide a bitmap buffer and native compiled code to encode the image data. It is straight forward to do:
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();
}
If you want to produce a different format than PNG (default) just specify the type like this:
return canvas.toDataURL('image/jpeg', quality); // quality = [0.0, 1.0]
Worth to note that CORS restrictions applies to toDataURL().
If your app is giving only base64 encoded images (I assume they are data-uri's with base64 data?) then you need to "load" the image first:
var img = new Image;
img.onload = resizeImage;
img.src = originalDataUriHere;
function resizeImage() {
var newDataUri = imageToDataUri(this, targetWidth, targetHeight);
// continue from here...
}
If the source is pure base-64 string simply add a header to it to make it a data-uri:
function base64ToDataUri(base64) {
return 'data:image/png;base64,' + base64;
}
Just replace the image/png part with the type the base64 string represents (ie. make it an optional argument).
Ken's answer is the right answer, but his code doesn't work. I made some adjustments on it and it now works perfectly. To resize a Data URI :
// Takes a data URI and returns the Data URI corresponding to the resized image at the wanted size.
function resizedataURL(datas, wantedWidth, wantedHeight)
{
// We create an image to receive the Data URI
var img = document.createElement('img');
// When the event "onload" is triggered we can resize the image.
img.onload = function()
{
// We create a canvas and get its context.
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// We set the dimensions at the wanted size.
canvas.width = wantedWidth;
canvas.height = wantedHeight;
// We resize the image with the canvas method drawImage();
ctx.drawImage(this, 0, 0, wantedWidth, wantedHeight);
var dataURI = canvas.toDataURL();
/////////////////////////////////////////
// Use and treat your Data URI here !! //
/////////////////////////////////////////
};
// We put the Data URI in the image's src attribute
img.src = datas;
}
// Use it like that : resizedataURL('yourDataURIHere', 50, 50);
Pierrick Martellière is far the best answer, I just wanted to point that you should implement that with a async function. Once that, you would be able to do something like:
var newDataUri = await resizedataURL(datas,600,600);
This will wait for the result of the function before going to the next step. It's a cleaner way to write code. Here is the function from Pierrick with the little edit:
// Takes a data URI and returns the Data URI corresponding to the resized image at the wanted size.
function resizedataURL(datas, wantedWidth, wantedHeight){
return new Promise(async function(resolve,reject){
// We create an image to receive the Data URI
var img = document.createElement('img');
// When the event "onload" is triggered we can resize the image.
img.onload = function()
{
// We create a canvas and get its context.
var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
// We set the dimensions at the wanted size.
canvas.width = wantedWidth;
canvas.height = wantedHeight;
// We resize the image with the canvas method drawImage();
ctx.drawImage(this, 0, 0, wantedWidth, wantedHeight);
var dataURI = canvas.toDataURL();
// This is the return of the Promise
resolve(dataURI);
};
// We put the Data URI in the image's src attribute
img.src = datas;
})
}// Use it like : var newDataURI = await resizedataURL('yourDataURIHere', 50, 50);
For more details you can check MDN Docs : https://developer.mozilla.org/fr/docs/Web/JavaScript/Reference/Objets_globaux/Promise
Yes, you can. These solutions good for resizing not just converting image to base64.
You can convert js file to image bitmap by jpg-js.And you can resize only by this lib, but in a case of resizing from very large image to very small, quality will be very bad.Best way for high-res images is to convert file to bitmap by jpg-js and then resize this bitmap by Pica lib.
You can get image data from a file by jpg-js (or draw an image on canvas)and then resize canvasImageData by resizing lib pica. (good for High-resolution images, without canvas size restriction)
You can use offscreen canvas, without attaching the canvas to a body, and resize an image. This solution will be faster but will be the worse solution for high-resolution images, for example 6000x6000 pixels. In that case, result canvas can be with bad quality or just empty, or browser can fall with memory limit exception. (good for normal and small images)
Jpg-js and Pica will not use dom elements at all. These libs are working only with image data, without dom elements (canvas and image).
About the canvas, size restriction see this post
I think this method is best way for this solution.
function base64Resize(sourceBase64, scale , callBack) {
const _scale = scale;
var img = document.createElement('img');
img.setAttribute("src", sourceBase64);
img.onload = () => {
var canvas = document.createElement('canvas');
canvas.width = img.width * _scale;
canvas.height = img.height * _scale;
var ctx = canvas.getContext("2d");
var cw = canvas.width;
var ch = canvas.height;
var maxW = img.width * _scale;
var maxH = img.height * _scale;
var iw = img.width;
var ih = img.height;
var scl = Math.min((maxW / iw), (maxH / ih));
var iwScaled = iw * scl;
var ihScaled = ih * scl;
canvas.width = iwScaled;
canvas.height = ihScaled;
ctx.drawImage(img, 0, 0, iwScaled, ihScaled);
const newBase64 = canvas.toDataURL("image/jpeg", scl);
callBack(newBase64);
}
}
Important point is that you should use img.onload event.
My last suggestion (as Chris) was deemed to not answer the question as it used canvas. Because canvas is too obvious.
It's not possible to do without loading the image into memory somewhere so it can be manipulated. Why not just use a library like jimp?
import Jimp from "jimp";
async function resizeBase64Image(base64: string, targetWidth: number, targetHeight: number): Promise<string> {
// Decode the base64 image data and save it to a buffer
const imageBuffer = Buffer.from(base64, "base64");
// Use Jimp to load the image from the buffer and resize it
const image = await Jimp.read(imageBuffer);
image.resize(targetWidth, targetHeight);
// Convert the image back to a base64 data URI
const resizedImageBase64 = await image.getBase64Async(Jimp.MIME_PNG);
return resizedImageBase64;
}
You may want a resize function that returns the resized data uri:
const resizeBase64Image = (base64: string, width: number, height: number): Promise<string> => {
// Create a canvas element
const canvas = document.createElement('canvas') as HTMLCanvasElement;
// Create an image element from the base64 string
const image = new Image();
image.src = base64;
// Return a Promise that resolves when the image has loaded
return new Promise((resolve, reject) => {
image.onload = () => {
// Calculate the aspect ratio of the image
const aspectRatio = image.width / image.height;
// Calculate the best fit dimensions for the canvas
if (width / height > aspectRatio) {
canvas.width = height * aspectRatio;
canvas.height = height;
} else {
canvas.width = width;
canvas.height = width / aspectRatio;
}
// Draw the image to the canvas
canvas.getContext('2d')!.drawImage(image, 0, 0, canvas.width, canvas.height);
// Resolve the Promise with the resized image as a base64 string
resolve(canvas.toDataURL());
};
image.onerror = reject;
});
};
And simply await it like this:
const resizedImage: string = await resizeBase64Image(base64, 100, 100);
function resizeImage(base64Str) {
var img = new Image();
img.src = base64Str;
var canvas = document.createElement('canvas');
var MAX_WIDTH = 400;
var MAX_HEIGHT = 350;
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);
return canvas.toDataURL();
}
https://gist.github.com/ORESoftware/ba5d03f3e1826dc15d5ad2bcec37f7bf

Canvas ImageData don't get more than 102,000 values?

I am getting pixels values from an image using canvas. The image size is 170*170 pixels. Here is my code:
var canvas = document.createElement("canvas");
canvas.style.width = img.width;
canvas.style.height = img.height;
canvas.getContext('2d').drawImage(img, 0, 0, img.width, img.height);
var pixelData = canvas.getContext('2d').getImageData(0, 0, img.width, img.height).data;
It works well, I have values in pixelData, until I reach pixelData[102000]... I've test it with a white image, and all the values from pixelData[0] to pixelData[101999] are 255, but then it is 0 until the end...
Somebody sees why? Maybe this is about canvas width and height?
Your canvas size is not what you think it is.
You are only setting the size of the canvas element not the canvas bitmap:
canvas.style.width = img.width;
canvas.style.height = img.height;
This means your bitmap is actually 300 x 150 pixels in size, the default size, and you're just scaling that to the size of the image (since it's all white you won't be able to detect this so easily).
Since your image is 170 x 170 pixels you will only paint part of the canvas leaving the rest to default RGBA value [0,0,0,0].
In order to properly set the size of the canvas you must edit the above mentioned lines to be:
canvas.width = img.width;
canvas.height = img.height;

Categories