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

Posted

技术标签:

【中文标题】如何在没有抗锯齿的情况下拉伸图像【英文标题】:How to stretch images with no antialiasing 【发布时间】:2012-01-25 16:38:41 【问题描述】:

所以我最近遇到了这个: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 似乎都停止支持它,因为我写了上面的内容(根据下面提到的this article),这真的很烦人。我们可能还需要再等几年才能真正开始在 CSS 中使用它,这真的很不幸。

最终编辑:现在有一种官方方法可以做到这一点!有一个名为image-rendering 的新属性。它在CSS3 spec 中。现在支持super spotty,但是Chrome just added support,所以不久之后我们就可以说image-rendering: pixelated;,它可以在所有地方工作(yaayy常青浏览器!)

【问题讨论】:

抗锯齿是一种用于平滑像素化边缘的技术。听起来您确实想使用抗锯齿功能。 @James 重点是保留像素化边缘,以获得复古效果。 scale() 方法呢? w3schools.com/TAGS/canvas_scale.asp.would 那行得通吗? 【参考方案1】:

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/ 的工作演示

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

【讨论】:

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

我已经把它用于画布

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

【讨论】:

在哪些浏览器中?不幸的是,它在 Chrome 中对我没有任何作用。还有 msImageSmoothingEnabled 可以添加到您的列表中。 混乱的解决方案 - 无意中为每个浏览器添加了前缀属性(对于错误的前缀)。将破坏随后访问该上下文并尝试检测正确前缀的任何其他代码。【参考方案3】:

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

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

【讨论】:

我在 Chrome、Firefox 和 MSIE 上试过你的小提琴 - 它不能正常工作 - 图像在每种情况下都经过抗锯齿处理。 在这里工作,Chrome 18 Mac OSX。它可能是特定于浏览器的东西。如果第一种方法不起作用,其他两种技术仍然值得研究。【参考方案4】:

不。浏览器无论如何都会这样做,并且您无法控制缩放算法。

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

【讨论】:

我在回答中完全做到了这一点。这并不难,而且足够快。【参考方案5】:

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

【讨论】:

以上是关于如何在没有抗锯齿的情况下拉伸图像的主要内容,如果未能解决你的问题,请参考以下文章

在 iOS 中,如何在没有抗锯齿/插值的情况下绘制位图?

如何在没有抗锯齿的情况下在画布上绘制像素字体

如何设置透明背景颜色并对 kivy 图像进行抗锯齿处理?

谷歌地图GroundOverlays默认情况下是不是具有抗锯齿功能?

如何在 pyqtgraph ImageView 中启用抗锯齿功能?

如何将非抗锯齿字体渲染到内部图像?