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>