Reputation: 450
Scaling the canvas up seems to be working fine but scaling down seems to be cutting off pixels. I've tried moving the order of things around and doing it without the in-memory-only canvas but nothing is working. My best guess is that the canvas is being sized down then scaled down further hence the reason the canvas data is not covering the entire canvas size.
// Create a newly scaled canvas from the original and then delete the original.
function ScaleCanvas(width, height, xScale, yScale) {
// Get the true overlay's current image data.
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
// Create an in-memory canvas at the new resolution.
const newCanvas = $("<canvas>")
.attr("width", width)
.attr("height", height)[0];
// Draw the true overlay's image data into the in-memory canvas.
newCanvas.getContext("2d").putImageData(imageData, 0, 0);
// Update the size/resolution of the true overlay.
ctx.canvas.width = width;
ctx.canvas.height = height;
// Scale the true overlay's context.
ctx.scale(xScale, yScale);
// Draw the in-memory canvas onto the true overlay.
ctx.drawImage(newCanvas, 0, 0);
}
There is a related question here where I got most of this logic: How to scale an imageData in HTML canvas?
The canvas is the appropriate resolution/size at the end of the function, but considering the fact that I have some pixels transparent and others opaque black it is obvious that the pixels at the right and bottom of the downscaled canvas are not producing the desired effect.
UPDATE Here is a jsfiddle to better illustrate the issue. Notice the one transparent pixel doesn't stay in the middle of the canvas after the canvas is scaled down.
Upvotes: 0
Views: 2251
Reputation: 570
I didn't manage to reproduce, so I tried to scale up and down canvas too and with the following code everything looks fine:
HTML:
<!doctype html>
<html>
<head>
<style>
canvas {
border: 1px solid red;
}
</style>
</head>
<body>
<canvas id="src" width="100" height="100"></canvas>
<canvas id="dest" width="100" height="100"></canvas>
<canvas id="src2" width="100" height="100"></canvas>
<canvas id="dest2" width="100" height="100"></canvas>
<script type="text/javascript" src="https://ajax.googleapis.com/ajax/libs/jquery/3.2.1/jquery.min.js"></script>
<script type="text/javascript" src="./main.js"></script>
</body>
</html>
JavaScript:
function scaleCanvas(srcCanvas, destCanvas, xScale, yScale) {
var destCtx = destCanvas.getContext("2d");
destCtx.scale(xScale, yScale);
destCtx.drawImage(srcCanvas, 0, 0);
}
window.onload = function() {
// Drawing on the source canvas for testing purpose
var srcCanvas = document.querySelector("#src");
var srcCtx = srcCanvas.getContext("2d");
var destCanvas = document.querySelector("#dest");
var image = new Image();
image.src = 'https://yt3.ggpht.com/-gAb9nWOBObg/AAAAAAAAAAI/AAAAAAAAAAA/CAZq5pc1dnY/s100-c-k-no-mo-rj-c0xffffff/photo.jpg';
image.onload = function() {
srcCtx.drawImage(image, 0, 0);
}
// ----
setTimeout(function() {
scaleCanvas(srcCanvas, destCanvas, 0.5, 0.5);
}, 1000);
};
Result:
Hope it can help.
EDIT (06/02/2018):
I wasn't sure to have well understood your issue. If I am correct, when you resize your canvas, the content isn't resized accordingly. So something in the center may not appear where it should after resizing, whereas it would have to be located in the center of the resized content, so that original proportions are kept. To illustrate, I added a medium sized red square in the middle (more visible than the transparent pixel):
Before resizing:
After resizing:
In fact, to achieve the downscale, you need to edit your ScaleCanvas call:
From this:
ScaleCanvas(75, 75, .75, .75);
To this:
ScaleCanvas(100, 100, .75, .75);
Only update the ratio, not the size of the canvas.
Here's what you get:
Before resizing:
After resizing:
Here's the fiddle: jsfiddle
I hope I've well understand your issue and that this fixes it. Otherwise comment below :)
EDIT (13/02/2018):
Okay, if you want to resize both the canvas and its content, the newly created canvas in the ScaleCanvas function must be the same size as the initial canvas. I updated the fiddle so that you can resize the canvas multiple times with a 50% ratio: updated jsfiddle. Notice the canvas's red border which shows that the canvas also reduces in size (not only the visual content).
Upvotes: 3