I have a canvas in my webpage; I create a new Image data in this canvas then I modify some pixel through myImgData.data[]
array. Now I would like to scale this image and make it bigger. I tried by scaling the context but the image remains small. Is it possible to do this?
Thanks
6 Answers
You could draw the imageData to a new canvas, scale the original canvas and then draw the new canvas to the original canvas.
Something like this should work:
var imageData = context.getImageData(0, 0, 100, 100);
var newCanvas = $("<canvas>")
.attr("width", imageData.width)
.attr("height", imageData.height)[0];
newCanvas.getContext("2d").putImageData(imageData, 0, 0);
context.scale(1.5, 1.5);
context.drawImage(newCanvas, 0, 0);
Here's a functioning demo http://jsfiddle.net/Hm2xq/2/.

- 29,855
- 23
- 108
- 144

- 8,525
- 5
- 39
- 66
-
21I would just like to add that you could do this without creating another canvas as ctx.drawImage(ctx.canvas,0,0); draws the canvas onto itself, and you can scale as you draw this. – Overcode May 12 '13 at 19:01
-
3but that scale also messes up coordinates 10 x is 1.5*10. How do you compensate for that – Muhammad Umer Nov 07 '14 at 04:14
-
i have same problem with this case: the newcanvas have alpha = 0 in some pixel. when drawing newcanvas to the original canvas. the alpha become black. how to solve this – billyzaelani Mar 15 '17 at 17:13
-
this is great tkhs! – wcandillon May 28 '23 at 20:52
I needed to do it without the interpolation that putImageData()
causes, so I did it by scaling the image data into a new, resized ImageData object. I can't think of any other time I've thought that using 5 nested for loops was a good idea:
function scaleImageData(imageData, scale) {
var scaled = c.createImageData(imageData.width * scale, imageData.height * scale);
for(var row = 0; row < imageData.height; row++) {
for(var col = 0; col < imageData.width; col++) {
var sourcePixel = [
imageData.data[(row * imageData.width + col) * 4 + 0],
imageData.data[(row * imageData.width + col) * 4 + 1],
imageData.data[(row * imageData.width + col) * 4 + 2],
imageData.data[(row * imageData.width + col) * 4 + 3]
];
for(var y = 0; y < scale; y++) {
var destRow = row * scale + y;
for(var x = 0; x < scale; x++) {
var destCol = col * scale + x;
for(var i = 0; i < 4; i++) {
scaled.data[(destRow * scaled.width + destCol) * 4 + i] =
sourcePixel[i];
}
}
}
}
}
return scaled;
}
I hope that at least one other programmer can copy and paste this into their editor while muttering, "There but for the grace of god go I."

- 29,855
- 23
- 108
- 144

- 14,878
- 5
- 30
- 33
-
Also it's possible to use more quality interpolation methods, such as bilinear or spline. – Ivan Kochurkin Jan 11 '13 at 08:29
-
3@KvanTTT totally true, although sometimes you want those chunky pixels. – Casey Rodarmor Sep 06 '13 at 12:08
-
2
-
2
-
1There's now an [imageSmoothingEnabled](https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/imageSmoothingEnabled) property that can be set to false in order to achieve nearest-neighbour interpolation on a scaled context. – Chunky Chunk Feb 14 '17 at 11:36
-
I know it's an old subject, but since people like may find it useful, I add my optimization to the code of rodarmor :
function scaleImageData(imageData, scale) {
var scaled = ctx.createImageData(imageData.width * scale, imageData.height * scale);
var subLine = ctx.createImageData(scale, 1).data
for (var row = 0; row < imageData.height; row++) {
for (var col = 0; col < imageData.width; col++) {
var sourcePixel = imageData.data.subarray(
(row * imageData.width + col) * 4,
(row * imageData.width + col) * 4 + 4
);
for (var x = 0; x < scale; x++) subLine.set(sourcePixel, x*4)
for (var y = 0; y < scale; y++) {
var destRow = row * scale + y;
var destCol = col * scale;
scaled.data.set(subLine, (destRow * scaled.width + destCol) * 4)
}
}
}
return scaled;
}
This code uses less loops and runs roughly 30 times faster. For instance, on a 100x zoom of a 100*100 area this codes takes 250 ms while the other takes more than 8 seconds.

- 181
- 1
- 2
You can scale the canvas using the drawImage method.
context = canvas.getContext('2d');
context.drawImage( canvas, 0, 0, 2*canvas.width, 2*canvas.height );
This would scale the image to double the size and render the north-west part of it to the canvas. Scaling is achieved with the third and fourth parameters to the drawImage method, which specify the resulting width and height of the image.
See docs at MDN https://developer.mozilla.org/en-US/docs/DOM/CanvasRenderingContext2D#drawImage%28%29

- 790
- 8
- 18
-
I don't understand... it draws the contents of a canvas onto that same canvas? – Stefan Reich Mar 19 '18 at 03:26
@Castrohenge's answer works, but as Muhammad Umer points out, it messes up the mouse coordinates on the original canvas after that. If you want to maintain the ability to perform additional scales (for cropping, etc.) then you need to utilize a second canvas (for scaling) and then fetch the image data from the second canvas and put that into the original canvas. Like so:
function scaleImageData(imageData, scale){
var newCanvas = $("<canvas>")
.attr("width", imageData.width)
.attr("height", imageData.height)[0];
newCanvas.getContext("2d").putImageData(imageData, 0, 0);
// Second canvas, for scaling
var scaleCanvas = $("<canvas>")
.attr("width", canvas.width)
.attr("height", canvas.height)[0];
var scaleCtx = scaleCanvas.getContext("2d");
scaleCtx.scale(scale, scale);
scaleCtx.drawImage(newCanvas, 0, 0);
var scaledImageData = scaleCtx.getImageData(0, 0, scaleCanvas.width, scaleCanvas.height);
return scaledImageData;
}

- 11,444
- 12
- 50
- 64
-
4for, `canvas.width`, and `canvas.height`, where is the variable `canvas` defined? – May 11 '17 at 23:26
Nowadays, the best way to render a scaled ImageData
object is generally to create an ImageBitmap from it.
All modern browsers finally do support it.
This will use a faster path to render the ImageData
's content to a bitmap readily available to be painted by drawImage()
, theoretically a lot faster than the second best option of putting the ImageData
on a secondary <canvas>
and redraw that <canvas>
.
The main catch-up is that createImageBitmap()
is asynchronous*, and thus it may not fit in an animation frame very well.
(async () => {
// here I'll just make some noise in my ImageData
const imagedata = new ImageData(100, 100);
const arr = new Uint32Array(imagedata.data.buffer);
for( let i = 0; i < arr.length; i++ ) {
arr[i] = Math.random() * 0xFFFFFF + 0xFF000000;
}
// now to render it bigger
const bitmap = await createImageBitmap(imagedata);
const canvas = document.querySelector("canvas");
const ctx = canvas.getContext("2d");
ctx.imageSmoothingEnabled = false; // keep pixel perfect
ctx.drawImage(bitmap, 0, 0, canvas.width, canvas.height);
})();
<canvas width="1000" height="1000"></canvas>
* Technically, only Firefox does implement createImageBitmap(<ImageData>)
asynchronously, Chrome and Safari will resolve the returned Promise synchronously, and there, it's safe to use it in an animation frame: https://jsfiddle.net/vraz3xcg/

- 123,334
- 13
- 219
- 285