如何在没有抗锯齿的情况下拉伸图像

IT技术 javascript css image image-manipulation
2021-01-20 10:21:49

所以我最近遇到了这个:http : //www.nicalis.com/

我很好奇:有没有办法用较小的图像来做这种事情?我的意思是,它是像素艺术,而不是使用每个像素大小增加四倍的图像,我们不能用代码拉伸它们吗?所以我开始尝试让它发生。

我尝试了 CSS、Javascript 甚至 HTML,但都没有奏效。它们都非常模糊(像这样:http : //jsfiddle.net/nUVJt/2/),这让我想到了我的问题:你能在没有任何抗锯齿的情况下在浏览器中拉伸图像吗?

我愿意接受任何建议,无论是使用画布、jQuery、CSS3 还是其他任何建议。

谢谢您的帮助!

编辑:现在有更好的方法来做到这一点!一种稍微不那么黑客的方式!这是魔法:

.pixelated {
    image-rendering: -moz-crisp-edges;
    image-rendering: -o-crisp-edges;
    image-rendering: -webkit-optimize-contrast;
    -ms-interpolation-mode: nearest-neighbor;
    image-rendering: pixelated;
}

这将停止所有现代浏览器中的抗锯齿。它甚至可以在 IE7-8 中工作,但不能在 9 中工作,不幸的是,我不知道在 9 中有什么方法(除了下面概述的画布黑客)。以这种方式这样做比使用 JS 快多少甚至都不好笑。以下是有关这些的更多信息:https : //developer.mozilla.org/en-US/docs/CSS/Image-rendering

EDIT2:因为这还不是官方规范,所以它不是很可靠。Chrome 和 FF 似乎都停止支持它,因为我写了上面的内容(根据下面提到的这篇文章),这真的很烦人。我们可能还得再等几年才能真正开始在 CSS 中使用它,这真的很不幸。

最终编辑:现在有一种官方方法可以做到这一点!有一个名为 的新属性image-rendering它在CSS3 规范中支持现在非常不稳定,但Chrome 刚刚添加了支持,所以不久我们就可以说它image-rendering: pixelated;可以在所有地方工作(yaayy 常青浏览器!)

5个回答

Canvas 文档明确没有指定缩放方法 - 在我自己的测试中,它确实在 Firefox 中对图像进行了非常糟糕的抗锯齿处理。

下面的代码从源图像(必须来自相同的 Origin 或来自数据 URI)中逐个像素地复制,并按指定的因子对其进行缩放。

需要额外的屏幕外画布 ( src_canvas) 来接收原始源图像,然后将其图像数据逐个像素复制到屏幕上画布中。

var img = new Image();
img.src = ...;
img.onload = function() {

    var scale = 8;

    var src_canvas = document.createElement('canvas');
    src_canvas.width = this.width;
    src_canvas.height = this.height;

    var src_ctx = src_canvas.getContext('2d');
    src_ctx.drawImage(this, 0, 0);
    var src_data = src_ctx.getImageData(0, 0, this.width, this.height).data;

    var dst_canvas = document.getElementById('canvas');
    dst_canvas.width = this.width * scale;
    dst_canvas.height = this.height * scale;
    var dst_ctx = dst_canvas.getContext('2d');

    var offset = 0;
    for (var y = 0; y < this.height; ++y) {
        for (var x = 0; x < this.width; ++x) {
            var r = src_data[offset++];
            var g = src_data[offset++];
            var b = src_data[offset++];
            var a = src_data[offset++] / 100.0;
            dst_ctx.fillStyle = 'rgba(' + [r, g, b, a].join(',') + ')';
            dst_ctx.fillRect(x * scale, y * scale, scale, scale);
        }
    }
};

http://jsfiddle.net/alnitak/LwJJR/ 上的工作演示

编辑http://jsfiddle.net/alnitak/j8YTe/提供了更优化的演示,演示还使用原始图像数据数组作为目标画布。

此外,看看您是如何做到这一点的,您可能会通过重新创建像素阵列而不是数千次fillRect调用来获得更好的性能循环数组并每 4 个值重复一次。
2021-03-15 10:21:49
@cwolves 是的,OP 的大图像在我的系统上花费了大约 120 毫秒。不过,这个fillRect方法更容易理解。
2021-03-15 10:21:49
@Timothy 最重要的部分是调用.getImageData()- 结果包括一个内存缓冲区(.data),其中包含当前画布中每个像素的 RGBA 值。两个嵌套循环只是读取该数据并在目标画布中绘制适当大小的方块。
2021-03-22 10:21:49
@cwolves 我制作了一个像素阵列复制版本 - jsfiddle.net/2Fkpc/1 - 在 30 毫秒和120毫秒内运行。
2021-03-31 10:21:49
不要低估您的解决方案(这正是我建议的),但是如果您正在做任何远程复杂的事情,这应该是最后的手段,因为它会很
2021-04-01 10:21:49

我已经把它用于画布

var canvas = document.getElementById("canvas"),
    context = canvas.getContext('2d');
context.webkitImageSmoothingEnabled = context.imageSmoothingEnabled = context.mozImageSmoothingEnabled = context.oImageSmoothingEnabled = false;
在哪些浏览器中?不幸的是,它在 Chrome 中对我没有任何作用。还有msImageSmoothingEnabled要添加到您的列表中。
2021-03-25 10:21:49
凌乱的解决方案 - 无意中向每个浏览器添加了前缀属性(对于错误的前缀)。将破坏随后访问该上下文并尝试检测正确前缀的任何其他代码。
2021-04-14 10:21:49

我能想到的唯一方法是通过画布。您可以尝试简单地将图像绘制到画布上,然后缩放画布——我认为您不会以这种方式抗锯齿。如果您仍然这样做,您可以尝试在绘制调用中缩放图像,或者如果不起作用,您可以使用getImageDataputImageData“手动”缩放图像

更新:第一种方法有效:http : //jsfiddle.net/nUVJt/3/

在这里工作,Chrome 18 Mac OSX。它可能是特定于浏览器的东西。如果第一个不起作用,其他两种技术仍然值得研究。
2021-04-06 10:21:49
我已经在 Chrome、Firefox 和 MSIE 上尝试过你的小提琴 - 它不能正常工作 - 在每种情况下图像都被抗锯齿。
2021-04-12 10:21:49

不。浏览器会这样做,但它会这样做,并且您无法控制缩放算法。

但是,我确定您可以制作基于画布的解决方案,但这可能涉及从源图像中复制像素并有策略地将它们绘制到画布中。这会很棘手,但可能(而且很慢)。

我已经在我的回答中做到了这一点。这并不难,而且速度足够快。
2021-04-11 10:21:49

我不确定,但也许您可以使用 imagedata。试试这个功能。。

function imageToImageData(image) {
     var canvas = document.createElement("canvas");
     canvas.width = image.width;
     canvas.height = image.height;
     var ctx = canvas.getContext("2d");
     ctx.drawImage(image, 0, 0);
     return ctx.getImageData(0, 0, canvas.width, canvas.height);
}