使用 javascript 画布调整图像大小(平滑)

2022-08-30 04:25:53

我正在尝试用画布调整一些图像的大小,但我不知道如何平滑它们。在photoshop,浏览器等上。他们使用了一些算法(例如双三次,双线性),但我不知道这些算法是否内置在画布中。

这是我的小提琴:http://jsfiddle.net/EWupT/

var canvas = document.createElement('canvas');
var ctx = canvas.getContext('2d');
canvas.width=300
canvas.height=234
ctx.drawImage(img, 0, 0, 300, 234);
document.body.appendChild(canvas);

第一个是正常调整大小的图像标记,第二个是画布。请注意画布的一个不那么光滑。如何实现“平滑度”?


答案 1

您可以使用下步来实现更好的结果。大多数浏览器在调整图像大小时似乎使用线性插值而不是双立方

(更新在规范中添加了一个质量属性,imageSmoothingQuality,目前仅在Chrome中可用。

除非选择不进行平滑或最近邻接,否则浏览器将始终在缩小图像后对其进行插值,因为此功能可用作低通滤波器以避免混叠。

双线性使用 2x2 像素进行插值,而双立方使用 4x4,因此通过分步进行,您可以在使用双线性插值的同时接近双立方结果,如结果图像所示。

var canvas = document.getElementById("canvas");
var ctx = canvas.getContext("2d");
var img = new Image();

img.onload = function () {

    // set size proportional to image
    canvas.height = canvas.width * (img.height / img.width);

    // step 1 - resize to 50%
    var oc = document.createElement('canvas'),
        octx = oc.getContext('2d');

    oc.width = img.width * 0.5;
    oc.height = img.height * 0.5;
    octx.drawImage(img, 0, 0, oc.width, oc.height);

    // step 2
    octx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5);

    // step 3, resize to final size
    ctx.drawImage(oc, 0, 0, oc.width * 0.5, oc.height * 0.5,
    0, 0, canvas.width, canvas.height);
}
img.src = "//i.imgur.com/SHo6Fub.jpg";
<img src="//i.imgur.com/SHo6Fub.jpg" width="300" height="234">
<canvas id="canvas" width=300></canvas>

根据调整大小的幅度,如果差异较小,则可以跳过步骤 2。

在演示中,您可以看到新结果现在与图像元素非常相似。


答案 2

由于Trung Le Nguyen Nhat的小提琴根本不正确(它只是在最后一步中使用了原始图像),
我写了自己的一般小提琴与性能比较:

小提琴

基本上是:

img.onload = function() {
   var canvas = document.createElement('canvas'),
       ctx = canvas.getContext("2d"),
       oc = document.createElement('canvas'),
       octx = oc.getContext('2d');

   canvas.width = width; // destination canvas size
   canvas.height = canvas.width * img.height / img.width;

   var cur = {
     width: Math.floor(img.width * 0.5),
     height: Math.floor(img.height * 0.5)
   }

   oc.width = cur.width;
   oc.height = cur.height;

   octx.drawImage(img, 0, 0, cur.width, cur.height);

   while (cur.width * 0.5 > width) {
     cur = {
       width: Math.floor(cur.width * 0.5),
       height: Math.floor(cur.height * 0.5)
     };
     octx.drawImage(oc, 0, 0, cur.width * 2, cur.height * 2, 0, 0, cur.width, cur.height);
   }

   ctx.drawImage(oc, 0, 0, cur.width, cur.height, 0, 0, canvas.width, canvas.height);
}