3

I am working on angular project and I have to put an image on a canvas. The image is not locally stored, I only have the image data so I use this.

this.context.putImageData(imgData, firstPointX, firstPointY);

Now my problem is that the picture I receive are 640 * 480. I was wondering if there is a way to change the image size so I can display larger than 640 * 480?

Daniel
  • 77
  • 1
  • 2
  • 10

2 Answers2

7

putImageData() will always use its own width and height for the destinationWidth and destinationHeight we could have in drawImage().

It is not sensible to the context matrix-transform, and thus scaling it will have no effect on this method.

One thing it has though is a dirtyWidth and a dirtyHeight arguments, which won't help us much since, while they can reduce the surface area that will get painted, they won't modify the contained pixels, and won't be able to make this surface grow anyway... (You can see this Q/A for a more in depth view about it)


To achieve what you want, you'd have to actually render your ImageData and then drawImage the rendered image.

The most comprehensive way to do so is probably using a second canvas:

var ctx = canvas.getContext('2d'),
  cW = canvas.width,
  cH = canvas.height,
  imgW = 20,
  imgH = 20;

// generate a 20*20 ImageData full of noise
var data = new Uint8Array(imgW * imgH * 4);
crypto.getRandomValues(data);
var img = new ImageData(new Uint8ClampedArray(data.buffer), imgW, imgH);


// generate a second canvas
var renderer = document.createElement('canvas');
renderer.width = img.width;
renderer.height = img.height;
// render our ImageData on this canvas
renderer.getContext('2d').putImageData(img, 0, 0);
// Now we can scale our image, by drawing our second canvas
ctx.drawImage(renderer, 0,0, cW, cH);
<canvas id="canvas" height="100" width="100"></canvas>

In modern browsers, this whole thing can be handled in a cleaner way, thanks to the ImageBitmap object:

var ctx = canvas.getContext('2d'),
  cW = canvas.width,
  cH = canvas.height,
  imgW = 20,
  imgH = 20;

// generate a 20*20 ImageData full of noise
var data = new Uint8Array(imgW * imgH * 4);
crypto.getRandomValues(data);
var img = new ImageData(new Uint8ClampedArray(data.buffer), imgW, imgH);

createImageBitmap(img).then(renderer => 
  ctx.drawImage(renderer, 0,0, cW, cH)
)
<canvas id="canvas" height="100" width="100"></canvas>

And a third way, only working for upscaling an ImageData and which will avoid a second canvas and be available in all implementations, is to use the same canvas as the ImageBitmap renderer, and draw this canvas onto itself using compositing:

var ctx = canvas.getContext('2d'),
  cW = canvas.width,
  cH = canvas.height,
  imgW = 20,
  imgH = 20;

// generate a 20*20 ImageData full of noise
var data = new Uint8Array(imgW * imgH * 4);
crypto.getRandomValues(data);
var img = new ImageData(new Uint8ClampedArray(data.buffer), imgW, imgH);

// we use the main canvas as renderer
ctx.putImageData(img, 0, 0);
// Now we have an unscaled version of our ImageData
// let's make the compositing mode to 'copy' so that our next drawing op erases whatever was there previously
// just like putImageData would have done
ctx.globalCompositeOperation = 'copy';
// now we can draw ourself over ourself.
ctx.drawImage(canvas,
  0,0, img.width, img.height, // grab the ImageData part
  0,0, canvas.width, canvas.height // scale it
);
<canvas id="canvas" height="100" width="100"></canvas>
Kaiido
  • 123,334
  • 13
  • 219
  • 285
2

The scale() method scales the current drawing, bigger or smaller.

this.context.putImageData(imgData, firstPointX, firstPointY);
this.context.scale(1.5,1.5);
this.context.drawImage(this.canvas, 0, 0); // <-- added
dAxx_
  • 2,210
  • 1
  • 18
  • 23
Chellappan வ
  • 23,645
  • 3
  • 29
  • 60
  • @Chellappan ,and Daniel, I've edited this answer so it works now, He just forgot to redraw the canvas after the scale. – dAxx_ Jul 17 '18 at 21:38