I'm trying to create a thumbnail image on the client side using javascript and a canvas element, but when I shrink the image down, it looks terrible. It looks as if it was downsized in photoshop with the resampling set to 'Nearest Neighbor' instead of Bicubic. I know its possible to get this to look right, because this site can do it just fine using a canvas as well. I've tried using the same code they do as shown in the "[Source]" link, but it still looks terrible. Is there something I'm missing, some setting that needs to be set or something?

编辑:

我正在调整一张jpg图片的大小。我试过在链接的网站和photoshop中调整相同的jpg图片的大小,缩小后看起来很好。

以下是相关代码:

reader.onloadend = function(e)
{
    var img = new Image();
    var ctx = canvas.getContext("2d");
    var canvasCopy = document.createElement("canvas");
    var copyContext = canvasCopy.getContext("2d");

    img.onload = function()
    {
        var ratio = 1;

        if(img.width > maxWidth)
            ratio = maxWidth / img.width;
        else if(img.height > maxHeight)
            ratio = maxHeight / img.height;

        canvasCopy.width = img.width;
        canvasCopy.height = img.height;
        copyContext.drawImage(img, 0, 0);

        canvas.width = img.width * ratio;
        canvas.height = img.height * ratio;
        ctx.drawImage(canvasCopy, 0, 0, canvasCopy.width, canvasCopy.height, 0, 0, canvas.width, canvas.height);
    };

    img.src = reader.result;
}

EDIT2:

看来我错了,链接网站并没有做任何更好的工作缩小图像。我尝试了其他建议的方法,没有一个看起来更好。这就是不同方法的结果:

ps:

帆布:

使用图像渲染:optimizeQuality设置并按宽度/高度缩放:

使用-moz-transform设置和缩放:

Canvas在pixastic上调整大小:

我猜这意味着firefox没有像它应该的那样使用双三次抽样。我只能等他们真的加进去了。

EDIT3:

原始图像


当前回答

我强烈建议你看看这个链接,并确保它被设置为真。

控制图像缩放行为 在Gecko 1.9.2 (Firefox 3.6)中引入 /雷鸟3.1 /耳廓1.0 Gecko 1.9.2引入了 mozImageSmoothingEnabled属性 canvas元素;如果这个布尔值 Value为false,图像不会为false 缩放时平滑。这个性质是 默认为True。看待plainprint ? 残雪。mozImageSmoothingEnabled = false;

其他回答

所以我发现了一些有趣的东西,在使用画布时可能会有所帮助:

要单独调整画布控件的大小,您需要使用height=""和width=""属性(或canvas.width/canvas. properties)。高度元素)。如果你使用CSS来调整画布的大小,它实际上会拉伸(即:调整大小)画布的内容以适应整个画布(而不是简单地增加或减少画布的面积)。

尝试将图像绘制到画布控件中,并将height和width属性设置为图像的大小,然后使用CSS将画布调整为您想要的大小,这是值得一试的。也许这将使用不同的调整大小算法。

还应该注意的是,canvas在不同浏览器(甚至不同浏览器的不同版本)中具有不同的效果。在浏览器中使用的算法和技术可能会随着时间的推移而改变(特别是Firefox 4和Chrome 6很快就会出来,这将非常强调画布渲染性能)。

此外,您可能也想尝试一下SVG,因为它可能也使用了不同的算法。

祝你好运!

快速和简单的Javascript图像调整器:

https://github.com/calvintwr/blitz-hermite-resize

const blitz = Blitz.create()

/* Promise */
blitz({
    source: DOM Image/DOM Canvas/jQuery/DataURL/File,
    width: 400,
    height: 600
}).then(output => {
    // handle output
})catch(error => {
    // handle error
})

/* Await */
let resized = await blizt({...})

/* Old school callback */
const blitz = Blitz.create('callback')
blitz({...}, function(output) {
    // run your callback.
})

历史

这是经过多轮研究、阅读和尝试后得出的结论。

调整器算法使用@ViliusL的Hermite脚本(Hermite调整器确实是最快的,并且提供了相当好的输出)。扩展了您需要的功能。

fork 1 worker来调整大小,这样它就不会在调整大小时冻结你的浏览器,不像其他所有的JS调整器。

我有一种感觉,我写的模块将产生类似于photoshop的结果,因为它通过平均颜色数据来保存它们,而不是应用算法。它有点慢,但对我来说是最好的,因为它保留了所有的颜色数据。

https://github.com/danschumann/limby-resize/blob/master/lib/canvas_resize.js

它不会选取最近的邻居并删除其他像素,也不会对一组进行抽样并随机取平均值。它取每个源像素输出到目标像素的精确比例。源点的平均像素颜色就是目标点的平均像素颜色,我认为其他公式不是这样的。

如何使用的例子是在底部 https://github.com/danschumann/limby-resize

2018年10月更新:这些天我的例子比其他任何东西都更学术。Webgl几乎是100%,所以你最好用它来调整大小,以产生类似的结果,但更快。我相信PICA.js就是这么做的。- - - - - -

我强烈建议你看看这个链接,并确保它被设置为真。

控制图像缩放行为 在Gecko 1.9.2 (Firefox 3.6)中引入 /雷鸟3.1 /耳廓1.0 Gecko 1.9.2引入了 mozImageSmoothingEnabled属性 canvas元素;如果这个布尔值 Value为false,图像不会为false 缩放时平滑。这个性质是 默认为True。看待plainprint ? 残雪。mozImageSmoothingEnabled = false;

其中一些解决方案的问题是,它们直接访问像素数据并通过它进行循环以执行下采样。根据图像的大小,这可能会非常消耗资源,最好使用浏览器的内部算法。

drawImage()函数使用线性插值、最近邻重采样方法。当您没有将大小调整到原来大小的一半以上时,这种方法效果很好。

如果循环一次只调整最大大小的一半,结果会非常好,而且比访问像素数据快得多。

这个函数每次采样到一半,直到达到所需的大小:

  function resize_image( src, dst, type, quality ) {
     var tmp = new Image(),
         canvas, context, cW, cH;

     type = type || 'image/jpeg';
     quality = quality || 0.92;

     cW = src.naturalWidth;
     cH = src.naturalHeight;

     tmp.src = src.src;
     tmp.onload = function() {

        canvas = document.createElement( 'canvas' );

        cW /= 2;
        cH /= 2;

        if ( cW < src.width ) cW = src.width;
        if ( cH < src.height ) cH = src.height;

        canvas.width = cW;
        canvas.height = cH;
        context = canvas.getContext( '2d' );
        context.drawImage( tmp, 0, 0, cW, cH );

        dst.src = canvas.toDataURL( type, quality );

        if ( cW <= src.width || cH <= src.height )
           return;

        tmp.src = dst.src;
     }

  }
  // The images sent as parameters can be in the DOM or be image objects
  resize_image( $( '#original' )[0], $( '#smaller' )[0] );

本文致谢