缩放图像以适应画布

我有一个表单,允许用户上传图片。

一旦加载了映像,我们就对其执行一些缩放操作,以便在将其传递回服务器之前减少其文件大小。

要做到这一点,我们把它放在画布上,并在那里操作它。

这段代码将在画布上呈现缩放后的图像,画布大小为320x240px:

ctx.drawImage(img, 0, 0, canvas.width, canvas.height)

... where canvas.width and canvas.height is the image height and width x a scaling factor based on the size of the original image.

但当我使用密码时:

ctx.drawImage(img, 0, 0, canvas.width, canvas.height, 0, 0, canvas.width, canvas.height

... 我只能看到画布上的一部分,这里是左上角。我需要整个图像’缩放’适合在画布上,尽管实际的图像大小比320x240画布大小。

因此,对于上面的代码,宽度和高度是1142x856,因为这是最终的图像大小。我需要保持这个大小,以便在表单提交时将 beck 传递给服务器,但是只希望在用户的画布中出现一个较小的视图。

我错过了什么? 有人能告诉我正确的方向吗?

Many thanks in advance.

144936 次浏览

提供源图像(img)大小作为第一个矩形:

ctx.drawImage(img, 0, 0, img.width,    img.height,     // source rectangle
0, 0, canvas.width, canvas.height); // destination rectangle

第二个矩形是目标大小(源矩形的缩放大小)。

更新2016/6 : 有关纵横比和定位(ala CSS 的“覆盖”方法) ,请查看:
模拟背景大小: 帆布覆盖

You made the error, for the second call, to set the size of source to the size of the target.
Anyway i bet that you want the same aspect ratio for the scaled image, so you need to compute it :

var hRatio = canvas.width / img.width    ;
var vRatio = canvas.height / img.height  ;
var ratio  = Math.min ( hRatio, vRatio );
ctx.drawImage(img, 0,0, img.width, img.height, 0,0,img.width*ratio, img.height*ratio);

我还假设你想把图像放在中间,这样代码就是:

function drawImageScaled(img, ctx) {
var canvas = ctx.canvas ;
var hRatio = canvas.width  / img.width    ;
var vRatio =  canvas.height / img.height  ;
var ratio  = Math.min ( hRatio, vRatio );
var centerShift_x = ( canvas.width - img.width*ratio ) / 2;
var centerShift_y = ( canvas.height - img.height*ratio ) / 2;
ctx.clearRect(0,0,canvas.width, canvas.height);
ctx.drawImage(img, 0,0, img.width, img.height,
centerShift_x,centerShift_y,img.width*ratio, img.height*ratio);
}

你可以在这里的 jsbin 中看到: Http://jsbin.com/funewofu/1/edit?js,output

我猜你想要的图像缩放到一个更小的尺寸,而不失去的尺寸比例。我有个办法。

var ratio = image.naturalWidth / image.naturalHeight;
var width = canvas.width;
var height = width / ratio;
ctx.drawImage(image, 0, 0, width, height);

比率将维持不变。在画布上绘制的图像将具有相同的比例。你可以使用 如果循环,如果图像的高度很长,你可以把 canvas.width替换成其他一些宽度

在拨打 ctx.drawImage之前,你可以先拨打 ctx.scale():

var factor  = Math.min ( canvas.width / img.width, canvas.height / img.height );
ctx.scale(factor, factor);
ctx.drawImage(img, 0, 0);
ctx.scale(1 / factor, 1 / factor);

这应该可以保持高宽比。

HTML:

<div id="root"></div>

JavaScript:

const images = [
'https://cdn.pixabay.com/photo/2022/07/25/15/18/cat-7344042_960_720.jpg',
'https://cdn.pixabay.com/photo/2022/06/27/08/37/monk-7287041_960_720.jpg',
'https://cdn.pixabay.com/photo/2022/07/18/19/57/dog-7330712_960_720.jpg',
'https://cdn.pixabay.com/photo/2022/05/22/18/25/spain-7214284_960_720.jpg',
];


const root = document.getElementById('root');


const image = new Image();
image.crossOrigin = 'anonumys';
image.src = images[3];


const canvas = document.createElement('canvas');
canvas.classList.add('track');
canvas.width = 600;
canvas.height = 400;
const ctx = canvas.getContext('2d');


const meta = {
ratio: image.width / image.height,
width: 0,
height: 0,
offsetX: 0,
offsetY: 0,
};


if (meta.ratio >= 1) {
meta.width = canvas.width > image.width ? image.width : canvas.width;
meta.height = meta.width / meta.ratio;
} else {
meta.height = canvas.height > image.height ? image.height : canvas.height;
meta.width = meta.height * meta.ratio;
}


meta.offsetX = canvas.width > meta.width ? (canvas.width - meta.width) / 2 : 0;
meta.offsetY = canvas.height > meta.height ? (canvas.height - meta.height) / 2 : 0;


image.addEventListener('load', () => {
ctx.drawImage(image, meta.offsetX, meta.offsetY, meta.width, meta.height);
root.append(canvas);
});


console.log(meta);