`
lizaochengwen
  • 浏览: 662439 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

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.   

创建前台画布:

var canvas = document.getElementById("_canvasView");
var context = canvas.getContext("2d");
创建后台画布:
  var backend = document.createElement("canvas");
  backend.width = canvas.width;
  backend.height = canvas.height;
  var backendContext = backend.getContext("2d");
// 后台画布涂上黑色(我相信anti-aliasing不会把它搞成灰色)

  backendContext.fillStyle = "#000000";
  backendContext.fillRect(0, 0, backend.width, backend.height);

// 获取后台画布对应的像素数组

  var imageObj = backendContext.getImageData( 0, 0, canvas.width, canvas.height);
  var imageData = imageObj.data;

如果你想给这个数组里的像素赋予颜色值,可以像下面的代码:
  function setPixel(imageData, width, height, x, y, red, green, blue)
  {
    // i 没做边界条件检查,留给读者自己完成。

    var i = (y*width+x)*4;
    imageData = red;
    imageData[i+1] = green;
    imageData[i+2] = blue;
    // 下面这个是Alpha,我们不用
    //DEL: imageData[i+3]=???;

  }

HTML5声称imageData是可以直接操控的。因此,这是我们良好的机会去直接设置像素值。把一个像素数组设置回绘图上下文和我写累了上厕所拉泡屎一样简单:
  backendContext.putImageData(imageData, 0, 0);
接下来是发挥你大学学习计算机图形学的智慧的时候了。

三、真的需要微积分么?微积分大家原理都知道,真正用的时候就发抖了。毕竟我们是写网页脚本的,研究基础代数可不是强项啊。微积分肯定是不需要的,因此计算机图形学也是不需要的。然而,的确有一种解决的办法,就是利用计算机图形学的知识。很底层啊,读者要有心理准备,别雷倒了。

view plainprint?

    function setPixel(imageData, W, H, x, y, r, g, b)  
    {  
      var i = (y*W+x)*4;  
      imageData = r;  
      imageData[i+1] = g;  
      imageData[i+2] = b;  
    }  
      
    /**
    * Bresenham's draw line algorithm
    */  
    function Bresenham_drawLine(imageData, width, height, x1, y1, x2, y2, r, g, b)  
    {  
      var dx = Math.abs(x2 - x1),  
          dy = Math.abs(y2 - y1),  
          yy = 0,  
          t;  
       
      if (dx < dy) {  
        yy = 1;  
        t=x1; x1=y1; y1=t;  
        t=x2; x2=y2; y2=t;  
        t=dx; dx=dy; dy=t;  
      }         
      
      var ix = (x2 - x1) > 0 ? 1 : -1,  
          iy = (y2 - y1) > 0 ? 1 : -1,  
          cx = x1,  
          cy = y1,  
          n2dy = dy * 2,  
          n2dydx = (dy - dx) * 2,  
          d = dy * 2 - dx;   
      
      if(yy==1) {     
        while(cx != x2) {  
          if(d < 0) {      
            d += n2dy;      
          }     
          else {      
            cy += iy;      
            d += n2dydx;      
          }  
      
          setPixel(imageData, width, height, cy, cx, r, g, b);  
          cx += ix;      
        }  
      }   
      else {     
        while(cx != x2) {      
          if(d < 0) {      
            d += n2dy;      
          }  
          else {      
            cy += iy;      
            d += n2dydx;      
          }  
       
          setPixel(imageData, width, height, cx, cy, r, g, b);      
          cx += ix;  
        }  
      }   
    }  
      
    /**
    * Bresenham's draw circle algorithm
    */  
    function _draw_circle_8(imageData, W, H, xc, yc, x, y, r, g, b)  
    {      
      setPixel(imageData, W, H, xc+x, yc+y, r, g, b);  
      setPixel(imageData, W, H, xc-x, yc+y, r, g, b);  
      setPixel(imageData, W, H, xc+x, yc-y, r, g, b);  
      setPixel(imageData, W, H, xc-x, yc-y, r, g, b);  
      setPixel(imageData, W, H, xc+y, yc+x, r, g, b);  
      setPixel(imageData, W, H, xc-y, yc+x, r, g, b);  
      setPixel(imageData, W, H, xc+y, yc-x, r, g, b);  
      setPixel(imageData, W, H, xc-y, yc-x, r, g, b);  
    }  
      
    function Bresenham_drawCircle(imageData, width, height, xc, yc, radius, fill, r, g, b)  
    {  
      var x = 0,  
          y = radius,  
          yi,  
          d = 3 - 2 * radius;  
      
      if (fill==1) {      
        while (x <= y) {      
          for (yi = x; yi <= y; yi ++) {   
            _draw_circle_8(imageData, width, height, xc, yc, x, yi, r, g, b);      
          }   
          if (d < 0) {      
            d = d + 4 * x + 6;      
          }     
          else {      
            d = d + 4 * (x - y);      
            y--;      
          }  
          x++;      
        }      
      }     
      else {      
        while (x <= y) {      
          _draw_circle_8(imageData, width, height, xc, yc, x, y, r, g, b);   
          if (d < 0) {      
            d = d + 4 * x + 6;      
          }     
          else {      
            d = d + 4 * (x - y);      
            y--;      
          }      
          x++;  
        }      
      }      
    }  

有个叫Bresenham的家伙,我们都要感谢他告诉我们怎么把一条线画到屏幕上。就是知道2个点坐标,从而知道如何点亮这条线经过的像素点的问题。我上面贴出来的代码不是卖弄我的图形学理论知识,实话说,代码是google出来的,我只是去伪存真而已。但是按上面的方法的确可以实现我要的去掉反走样,看看我工作的截图:

上面这个图就是带有反走样的前台画布的现实效果。而下面的这个就是后台画布去掉反走样的现实效果。我就是采用上面的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);  
    }
分享到:
评论

相关推荐

    HTML5Canvas如何取消反锯齿绘图

    HTML5Canvas的绘图就是默认anti-aliasing的。其实作为一般的开发者,可以不关心这个东西的存在,好像anti-aliasing是理应如此的。但是,如果我们的用户非要看到non-anti-aliasing的效果呢?这个类似有了酱油还要吃盐...

    delphi用canvas画线搞锯齿demo

    2. **使用Canvas的内置方法**:虽然Delphi的Canvas对象没有直接提供抗锯齿功能,但可以通过调整Canvas的绘图模式来间接实现。例如,可以在画线前调用Canvas.SetPixelFormat函数,选择支持抗锯齿的像素格式。然后,...

    详解Html5 Canvas画线有毛边解决方法

    Html5 Canvas画线有毛边是一个在Web前端开发中常见的问题,特别是在使用Canvas 2D渲染图形时。这个问题主要是由于Canvas中坐标点与像素点之间的对齐问题造成的。下面我们将详细探讨这个问题及解决方案。 **Canvas...

    html5 canvas鼠标跟随线条动画特效

    HTML5 Canvas是一个强大的Web绘图工具,允许开发者在网页上直接进行图形绘制,提供丰富的API接口,使得动态和交互式的视觉效果得以实现。本案例中,“html5 canvas鼠标跟随线条动画特效”是一个利用Canvas API创建的...

    HTML5 Canvas锯齿图代码实例

    总而言之,HTML5 Canvas锯齿图代码实例为我们展示了一种简单的技术手段,通过特定的绘图代码,我们可以直观地看到和理解锯齿图的产生原理,并且在此基础上可以进一步探讨和应用相关的图形处理技术,以达到优化视觉...

    html5 canvas简洁的涂鸦画板代码

    HTML5 Canvas是Web开发中的一个强大工具,它允许开发者在网页上进行图形绘制,提供了丰富的绘图API,使得创建交互式或动态的图形成为可能。在这个"html5 canvas简洁的涂鸦画板代码"示例中,我们将深入探讨如何利用...

    Html5_Canvas绘制心电图

    HTML5 Canvas是Web开发中的一个强大工具,它允许开发者在网页上进行动态图形绘制。在这个“Html5_Canvas绘制心电图”的项目中,我们将深入探讨如何利用Canvas API来模拟心电图(ECG)的显示。心电图是一种记录心脏电...

    HTML5canvas写的酷炫钟表

    首先,HTML5 Canvas是通过JavaScript API来使用的,它提供了绘图的基本功能,如画线、填充形状、绘制文本和图片等。在"HTML5 Canvas写的酷炫钟表"中,开发者会用到`canvas`元素,这是一个HTML标签,用于在页面上创建...

    玩转html5 的 canvas画图

    Canvas是像素化的,因此所有的绘图都是位图,这意味着它依赖分辨率,并且可能会出现锯齿边缘。 Canvas的使用从HTML文档中的一个简单的&lt;canvas&gt;标签开始。这个标签需要一个id和width、height属性来定义画布的尺寸。...

    HTML5 canvas 项目之时钟.rar

    HTML5的canvas元素是网页开发中的一个强大工具,它提供了在网页上绘制图形的能力,无需依赖Flash或其他插件。在这个“HTML5 canvas 项目之时钟”中,我们可以通过JavaScript脚本利用canvas API来创建动态的时钟效果...

    Android-使用clippath实现的CircleImageView没有Bitmap没有锯齿

    5. **注意事项**:为了防止Bitmap拉伸导致的锯齿现象,最好使用高分辨率的图片,并且在设置Bitmap时使用`_antialiasing`属性来开启抗锯齿,以提高显示质量。 6. **使用CircleImageView**:在布局文件中,将普通的`...

    html5+canvas绘制七巧板特效源码.zip

    Canvas是HTML5的一个核心特性,它提供了一个二维绘图环境,允许开发者通过JavaScript来绘制图形,进行动画制作等复杂操作。 首先,Canvas是一个基于矢量图形的画布,这意味着它可以无损地缩放,并且支持抗锯齿效果...

    canvas、paint绘图

    在Android开发中,Canvas和Paint是两个至关重要的类,它们为开发者...TestPaintActivity这个示例代码很可能会包含上述提到的一些绘图技巧,通过查看和理解这些代码,可以进一步巩固和提升你的Canvas和Paint使用技能。

    Android Canvas绘图Demo

    本篇将深入探讨`Android Canvas绘图`的相关知识点,包括基本概念、常用方法以及实际应用。 一、Canvas基础 1. `Canvas`对象:在Android中,`Canvas`是绘画的基础,它就像一块画布,我们可以在上面绘制各种元素。...

    html5 canvas实现涂鸦写字板效果

    HTML5 Canvas 是一种在网页上绘制图形的API,它允许开发者直接在网页上进行动态图形绘制,无需借助Flash或其他插件。"html5 canvas实现涂鸦写字板效果"是一个使用Canvas API创建的交互式功能,让用户可以在网页上...

    html5 canvas实现粒子流体汇聚的爱心动画特效源码.zip

    总的来说,这个压缩包提供了一个学习HTML5 Canvas技术和粒子动画的实践案例,适合前端开发者深入理解Canvas的绘图原理,以及如何通过编程实现复杂动画效果。通过分析和修改这段源码,你可以进一步提升在Web图形编程...

    canvas绘图缩放算法

    在计算机图形学中,canvas是HTML5提供的一种强大的绘图工具,允许开发者在网页上进行动态的、基于JavaScript的2D绘图。本主题聚焦于"canvas绘图缩放算法",尤其是以多边形中心点为基准进行缩放的过程。这种算法在...

    绘图基础Canvas+Path+Paint

    总结来说,Canvas是绘图的基础,提供绘图区域;Path是图形路径,可以构建复杂形状;Paint则负责图形的样式和外观。三者结合,开发者可以实现各种定制化的界面设计,创造出丰富多样的视觉效果。在Android开发中,理解...

    html5基于canvas实现的圆形时钟效果源码.zip

    Canvas是HTML5的一个核心元素,它提供了一个二维绘图环境,允许JavaScript直接在网页上绘制图形。通过调用Canvas上的方法,我们可以控制线条、形状、颜色等元素,创建出各种复杂的视觉效果。在这个例子中,开发者...

Global site tag (gtag.js) - Google Analytics