如何在没有反锯齿的情况下拉伸图片

41

最近我遇到了这个网站: http://www.nicalis.com/

我很好奇: 是否有办法用更小的图像实现这种效果呢?我的意思是,它是像素艺术,而不是使用每个像素四倍大小的图像,我们能否通过代码来拉伸它们? 所以我开始尝试让它发生。

我尝试了CSS,Javascript,甚至HTML,但都没有成功。它们都会模糊得很厉害(就像这样: http://jsfiddle.net/nUVJt/2/),这就带来了我的问题: 你能在浏览器中拉伸图像而不进行任何抗锯齿处理吗?

我对任何建议都持开放态度,无论是使用画布、jQuery、CSS3或其他方法。

感谢您的帮助!

编辑: 现在有更好的方法了! 一个稍微不那么hackish的方法! 这里是魔法:

.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中如何实现它,不幸的是(除了下面概述的画布hack)。用这种方式做比用JS快得多,这真的很有趣。这里有更多关于它们的信息:https://developer.mozilla.org/en-US/docs/CSS/Image-rendering

编辑2:因为这还不是一个官方规范,所以它不是非常可靠。自从我写上面的内容以来,Chrome和FF似乎都停止支持它(根据下面提到的this article),这真的很烦人。我们可能需要再等几年才能真正开始在CSS中使用它,这真的很不幸。

最终编辑:现在有一种官方的方法可以做到这一点!有一个叫做image-rendering的新属性。它在CSS3规范中。目前支持非常不稳定,但是Chrome刚刚添加了支持,所以不久之后我们就可以只说image-rendering: pixelated;,它将在所有地方起作用(耶,永远绿色的浏览器!)

抗锯齿是一种用于平滑像素边缘的技术。听起来你确实想使用抗锯齿。 - James
8
@James 整个意图是要“保留”像素化的边缘,以产生复古效果。 - Alnitak
scale() 方法怎么样?http://www.w3schools.com/TAGS/canvas_scale.asp。那个行得通吗? - Jess
5个回答

19
< p>Canvas文档明确未指定缩放方法—在我的测试中,Firefox中的图像确实出现了严重的抗锯齿问题。

以下代码逐像素从源图像(必须来自相同的Origin或Data 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/上有更加高效的演示,该演示还使用了原始图像数据数组作为目标画布。


1
@Timothy,关键部分是调用.getImageData()函数 - 其结果包括一个内存缓冲区(.data),其中包含当前画布中每个像素的RGBA值。两个嵌套循环只是读取该数据并在目标画布中绘制适当大小的正方形。 - Alnitak
3
不是贬低你的解决方案(它就是我建议的),但如果你要做任何稍微复杂一点的事情,这应该是最后的选择,因为它会非常_慢_。 - user578895
1
此外,从您的实现方式看,通过重新创建像素数组而不是调用数千个 fillRect 方法,您可能会获得更好的性能。循环该数组并复制每四个值。 - user578895
@cwolves 是的,在我的系统上处理OP的大图大约需要120毫秒。不过,fillRect方法更容易理解。 - Alnitak
@cwolves 我制作了一个像素数组复制版本 - http://jsfiddle.net/2Fkpc/1/ - 运行时间为30毫秒,而不是120毫秒。 - Alnitak
显示剩余3条评论

4

我已经让这个在canvas上运行起来了。

var canvas = document.getElementById("canvas"),
    context = canvas.getContext('2d');
context.webkitImageSmoothingEnabled = context.imageSmoothingEnabled = context.mozImageSmoothingEnabled = context.oImageSmoothingEnabled = false;

在哪些浏览器中?不幸的是,在Chrome中它对我没有任何作用。此外,还有msImageSmoothingEnabled要添加到您的列表中。 - Drew Noakes
混乱的解决方案 - 无意中向每个浏览器(使用错误的前缀)添加了前缀属性。这将破坏随后访问该上下文并尝试检测正确前缀的任何其他代码。 - Alnitak

1

我所想到的唯一方法是通过canvas。您可以尝试将图像简单地绘制到画布上,然后缩放画布 - 我认为这样不会出现反锯齿效果。如果仍然存在,则可以尝试在绘制调用中缩放图像,或者如果那也不起作用,则可以使用getImageDataputImageData手动缩放图像。

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


我已经在Chrome,Firefox和MSIE上尝试了你的fiddle - 它不能正确地工作 - 在每种情况下图像都是抗锯齿的。 - Alnitak
可以在这里运行,Chrome 18 Mac OSX。这可能是一个特定于浏览器的问题。如果第一种方法不起作用,仍然值得尝试另外两种技术。 - user578895

0

不行。浏览器会按照自己的方式进行缩放,你无法控制缩放算法。

但是,我相信你可以通过基于画布的解决方案来实现,但这可能涉及从源图像中复制像素并将其策略性地绘制到画布中。这很棘手,但是有可能(而且速度较慢)。


2
我在我的答案中已经做到了这一点。 这并不难,而且速度足够快。 - Alnitak

0

我不确定,但也许你可以使用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);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接