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:

原始图像


当前回答

我有一种感觉,我写的模块将产生类似于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就是这么做的。- - - - - -

其他回答

快速和简单的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调整器。

为了调整图像的宽度小于原始,我使用:

    function resize2(i) {
      var cc = document.createElement("canvas");
      cc.width = i.width / 2;
      cc.height = i.height / 2;
      var ctx = cc.getContext("2d");
      ctx.drawImage(i, 0, 0, cc.width, cc.height);
      return cc;
    }
    var cc = img;
    while (cc.width > 64 * 2) {
      cc = resize2(cc);
    }
    // .. than drawImage(cc, .... )

它工作=)。

我有一种感觉,我写的模块将产生类似于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就是这么做的。- - - - - -

我想从答案中得到一些定义良好的函数,所以最后得到了这些,我希望对其他人也有用,

function getImageFromLink(link) {
    return new Promise(function (resolve) {
        var image = new Image();
        image.onload = function () { resolve(image); };
        image.src = link;
    });
}

function resizeImageToBlob(image, width, height, mime) {
    return new Promise(function (resolve) {
        var canvas = document.createElement('canvas');
        canvas.width = width;
        canvas.height = height;
        canvas.getContext('2d').drawImage(image, 0, 0, width, height);
        return canvas.toBlob(resolve, mime);
    });
}

getImageFromLink(location.href).then(function (image) {
    // calculate these based on the original size
    var width = image.width / 4;
    var height = image.height / 4;
    return resizeImageToBlob(image, width, height, 'image/jpeg');
}).then(function (blob) {
    // Do something with the result Blob object
    document.querySelector('img').src = URL.createObjectURL(blob);
});

为了测试这个,在一个标签中打开的图像上运行它。

我知道这是一个老话题,但它可能对像我这样的人有用,几个月后,我们第一次遇到这个问题。

这里有一些代码,可以在每次重新加载图像时调整图像的大小。我知道这根本不是最优的,但我提供它作为概念的证明。

另外,很抱歉使用jQuery来做简单的选择器,但我觉得语法太舒服了。

$(document).on('ready', createImage); $(window).on('resize', createImage); var createImage = function(){ var canvas = document.getElementById('myCanvas'); canvas.width = window.innerWidth || $(window).width(); canvas.height = window.innerHeight || $(window).height(); var ctx = canvas.getContext('2d'); img = new Image(); img.addEventListener('load', function () { ctx.drawImage(this, 0, 0, w, h); }); img.src = 'http://www.ruinvalor.com/Telanor/images/original.jpg'; }; html, body{ height: 100%; width: 100%; margin: 0; padding: 0; background: #000; } canvas{ position: absolute; left: 0; top: 0; z-index: 0; } <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script> <html> <head> <meta charset="utf-8" /> <title>Canvas Resize</title> </head> <body> <canvas id="myCanvas"></canvas> </body> </html>

我的createImage函数在文档加载时被调用一次,之后每次窗口接收到调整大小事件时都被调用。

我在Mac电脑上的Chrome 6和Firefox 3.6中进行了测试。这种“技术”对处理器的消耗就像夏天的冰淇淋一样,但它确实奏效了。