首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 网站开发 > CSS >

HTML5 Canvas 怎么取消反锯齿绘图

2012-08-26 
HTML5 Canvas 如何取消反锯齿绘图HTML5 Canvas 如何取消反锯齿绘图(HTML5 Canvas how to turn off anti-al

HTML5 Canvas 如何取消反锯齿绘图
HTML5 Canvas 如何取消反锯齿绘图(HTML5 Canvas how to turn off anti-aliasing drawing)一、问题的提出
我们都知道反锯齿(anti-aliasing)绘图给我们带来更好的视觉体验,有了这个技术,绘制的图形的边缘再不是以前毛毛躁躁的样子了。这就是采用反锯齿算法的功劳。其实质就是把要绘制的颜色边缘和背景颜色做适当的融合,在人的眼睛看来,有种像雾像雨又像风的感觉。HTML5 Canvas的绘图就是默认anti-aliasing的。其实作为一般的开发者,可以不关心这个东西的存在,好像anti-aliasing是理应如此的。但是,如果我们的用户非要看到non-anti-aliasing的效果呢?
这个类似有了酱油还要吃盐的问题。酱油是好,但是有人就是要吃盐,怎么办?
另外的需求是,即使有了酱油,我还是需要吃盐。为啥,酱油有它的好处,盐有盐的用处。
比如:当我们在Canvas上移动鼠标的时候,我需要知道我的鼠标位置在什么图形上,即著名的点选问题。Canvas以前的绘图软件解决这个问题有标准的方法,就是用图形的ID作为图形的颜色值,绘制在内存当中的后台画布上,当我们移动鼠标在前台显示的画布上,我们可以通过获取后台画布的该点的像素值(ID)来获得图形ID。
这样一切都近乎完美。后台画布与前台画布采用完全一样的绘图机制,不同点是前台画布采用用户看到的实际像素颜色值,而后台画布采用图形的ID作为图形绘制的像素颜色值。这里的前提是,我们能控制这些像素值,以确保它在被绘制到后台画布的时候不被改变,就是我让你画一个像素颜色=1,你别自作聪明搞出个=1.5。遗憾的是目前版本的HTML5 Canvas就是这种自作聪明的家伙。迄今为止,我们没办法控制去掉anti-aliasing这个自作聪明的算法。我试过即使把context.mozImageSmoothingEnabled=false也不行。
如果这儿谁有一句话的方法可以满足我上面讲的需求,那么这篇文章直接就等于是狗屎。我费了很多的努力研究出了这篇狗屎文,在这里以飨读者,包括我自己。
二、解决方法探讨
如何取消(废止)HTML5 Canvas的反锯齿功能,在http://stackoverflow.com上也有很多讨论。如果让HTML5实现者来解决这个问题,几乎就是一句话搞定的事情。然而需要我们一周的时间想各种点子。在HTML5 Canvas本身没解决这个问题之前,如果让有的人来解决,几乎要花掉几个月的时间,好在如果你看到这篇文章,你就可以告诉你的老板,你只需要几个晚上就可以解决了。下面我教你具体办法。
前台画布我不管它,你怎么画是你自己的问题,后台画布和前台一样大小,涂满黑色(#000000)。然后你在前台Canvas上画图形id=1的时候,同时在后台画布上用1为颜色画这个同样的图形。对了,我还没告诉你如何去掉anti-aliasing,如果不去掉anti-aliasing,系统可能给画出来的像素颜色是1.5,这显然不是你想要的,也不是我写这篇狗屎文的目的。
我只好用代码来说明问题。记住这是HTML5的代码,javascript而已。
在HTML5页面中有Canvas:
          This browser does not support HTML5 Canvas.   


上面这个图就是带有反走样的前台画布的现实效果。而下面的这个就是后台画布去掉反走样的现实效果。我就是采用上面的Bresenham算法来实现的,运行效率还蛮高的。

其实用这种办法,新带来的问题比原来的更多更复杂:

1)都HTML5时代了,还要Bresenham这个老家伙出来壮场子,当我白痴啊。

2)写脚本的一般都是算法小白,这样会吓傻人的。

3)HTML5 Canvas如果真是这样用,岂不是更大的退步吗?

4)最大的困难是那么多图形类型,每个都要用Bresenham算法搞定,不是太2了么?
四、你可能需要第三块画布第三块画布是个即擦即用的画布,我称它为Swapped Canvas。有了它,Bresenham算法就滚蛋了。过程如下:
1)前台画布每画一个图形G,就在第三块画布上画同样的图形G,前提是第三块画布上每次画图形之前都清空(涂黑)。这就是即擦即用的意思。不要以为我打错字了(不是插),我没那么傻B。
2)然后取得第三块画布的图像像素数组,遍历图形G所在范围矩形内的全部像素p(i,j),如果像素值v=p(i,j)=0为黑,就忽略,否则就到后台画布相应的位置p(i,j)上用G的ID作为颜色填上p(i,j)=ID。
最后我们得到的后台画布一定是没有反锯齿的家伙。好了,anti-aliasing,滚你马蛋吧。

最后整个过程的伪代码如下:

view plainprint?    // 遍历全部图形      for (ShapeId=1, 2, 3, ...)      {          // 取得每个要绘制的图形在画布上的像素坐标范围rect=(x0,y0,w,h)          rect = getDrawShapeRect(ShapeId);                // 画图形到前台画布上          drawShapeOnForeground(ShapeId);                    // 设置清除中间画布指定区域的颜色为0(黑色 BlackColor)          fillSwappedBlackColor(rect);                    // 采用白色画笔和刷子绘制图形到中间画布上          drawShapeOnSwappedWithWhiteColor(ShapeId);                // 遍历中间画布的rect区域内的所有像素          for (x=x0; x    {              for (y=y0; y        {                  // 如果像素点有值(不是黑色)                  if (getSwappedPixelColor(x, y) != BlackColor)                  {                      // 在后台画布上设置对应点的像素为当前图形ID                      setBackendPixelColor(x, y, ShapeId);                  }              }          }      }            // 点选返回图形ID (0:未选中)      HitTest(x, y)      {        return getBackendPixelColor(x, y);      }

热点排行