调整画布图像大小而不使其模糊
Posted
技术标签:
【中文标题】调整画布图像大小而不使其模糊【英文标题】:Resizing a canvas image without blurring it 【发布时间】:2013-09-04 00:25:22 【问题描述】:我有一个小图像,我正在画布上渲染,如下所示:
ctx.drawImage(img, 0, 0, img.width*2, img.height*2);
我希望它显示一个清晰的放大图像(每个图像像素 4 个相同的像素)。但是,此代码(在 Mac 上的 Chrome 29 中)会产生模糊的图像。在 Photoshop 术语中,它看起来像是在使用“双三次”重采样,而不是“最近邻”。
在有用的情况下(例如复古游戏),是否可以生成清晰的放大图像,或者我是否需要在服务器上为每种尺寸的图像创建一个单独的图像文件?
【问题讨论】:
最好的方法是为每种尺寸分别设置图像(最快、质量好),另一种方法是先拥有最大的然后随时调整它们的大小(最小的存储空间、高质量)。 @slash197 如果我缩小比例,它会有同样的模糊。 不应该模糊,你保持纵横比吗? 查看这个问题的答案***.com/questions/2303690/…。实际上,您的问题似乎与此重复。 @slash197 我的错。经过进一步测试,它实际上正在正确缩小规模。这样做似乎很浪费带宽,但我仍然希望有一个解决方案。 【参考方案1】:只需关闭画布的图像抗锯齿功能 - 不幸的是,这个属性仍然是供应商前缀,所以这里有一些变化:
context.webkitImageSmoothingEnabled = false;
context.mozImageSmoothingEnabled = false;
context.imageSmoothingEnabled = false;
然后绘制图像。
对于尚未实现此功能的旧版本和浏览器,您可以选择使用 CSS:
canvas
image-rendering: optimizeSpeed; // Older versions of FF
image-rendering: -moz-crisp-edges; // FF 6.0+
image-rendering: -webkit-optimize-contrast; // Webkit (non standard naming)
image-rendering: -o-crisp-edges; // OS X & Windows Opera (12.02+)
image-rendering: crisp-edges; // Possible future browsers.
-ms-interpolation-mode: nearest-neighbor; // IE (non standard naming)
ONLINE TEST HERE
【讨论】:
太棒了,比缩小大文件或getImageData
更好(也更优雅)的解决方案。
无前缀 context.imageSmoothingEnabled
在 Chrome 中至少从版本 33 开始工作。【参考方案2】:
检查这个小提琴:http://jsfiddle.net/yPFjg/
它将图像加载到画布中,然后创建一个调整大小的副本并将其用作精灵。
只需少量修改,您就可以实现一个动态调整图像大小的图像加载器。
var ctx = document.getElementById('canvas1').getContext('2d');
var img = new Image();
var original = document.createElement("canvas");
var scaled = document.createElement("canvas");
img.onload = function()
var oc = original.getContext('2d');
var sc = scaled.getContext('2d');
oc.canvas.width = oc.canvas.height = 16;
sc.canvas.width = sc.canvas.height = 32;
oc.drawImage(this, 0, 0);
var od = oc.getImageData(0,0,16,16);
var sd = sc.getImageData(0,0,32,32);
for (var x=0; x<32; x++)
for (var y=0; y<32; y++)
for (var c=0; c<4; c++)
// you can improve these calculations, I let them so for clarity
sd.data[(y*32+x)*4+c] = od.data[((y>>1)*16+(x>>1))*4+c];
sc.putImageData(sd, 0, 0);
ctx.drawImage(scaled, 0, 0);
img.src = document.getElementById('sprite').src;
关于 getImageData 的一些注意事项:它返回一个带有数组的对象。该数组的大小为高*宽*4。颜色分量按 RGBA 顺序存储(红、绿、蓝、alpha,每个值 8 位)。
【讨论】:
这在 Firefox 中对我不起作用(JS 控制台中没有错误)。 i.imgur.com/DDqlxTS.png 固定为 FF。我已经更改了图像创建(第 2 行)以上是关于调整画布图像大小而不使其模糊的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Xcode 的 Storyboard 中保持高分辨率图像而不使其像素化?