zoukankan      html  css  js  c++  java
  • 我记录网站综合系统 技术原理解析[2:C# 水印和验证码的制作]

    代码位置:wojilu\Drawing\Watermark.cs

    水印的定义:水印一般是指在图片上的一些版权信息文字,或者为了某种目的而对原始图片上附加一些图形或者文字。

    水印的基本制作方法就是使用GDI+的方法在图片的制定位置上绘制文字或者图片。

    说到GDI+,一般用于Winform对于GUI的绘制,例如文本编辑器的制作,就是使用GDI函数绘制文字在窗体表面。其实GDI不仅可以绘制窗体,它可以绘制一切的Drawable的表面。

    我记录的水印制作就是利用GDI函数,进行原图和水印图片的合并,或者在原图上绘制文字。

    关键GDI函数:(System.Drawing.Graphics 类的方法)

    DrawImage  绘制图片

    DrawString  绘制文字

    这两个函数有大量的重载,具体请查阅MSDN。


     水印图片:

        水印图片一般是使用纯绿或者纯蓝背景色的图片,就和拍摄电影一样,在拍摄的时候,演员在绿色背景里面演戏,在后期制作的时候,绿色的背景都会被透明色所取代掉。在C#里面,我们使用SetRemapTable这个图像特性来完成这个工作。它的作用是让图片上面某个颜色被另一种颜色所替换掉。OldColor 就是要被取代掉的颜色,NewColor则是新的颜色。5-10行则是完成这样的操作。

         接下来就是将图片的所有点的透明度下降为原来的30%。这里将使用ColorMatrix来做。矩阵,在很多地方被大量使用,特别是变换的地方,例如图片的拉伸,缩放等等,都是利用了矩阵乘法的快速运算。这里也使用了矩阵来进行全像素的高速变换。仔细观察12行的矩阵的对角线上的数字:1,1,1,0.3,1 这些是倍数运算因子。对应则RGBAW的变换倍数。RGB不变,透明度为原来的0.3倍。W也不变。通过这种方法,就将图片的透明度降低了。

        这些颜色变换,在Draw方法执行时候,才进行变换。

     1         private static ImageAttributes getImageAttributes() {
     2 
     3             ImageAttributes imgAttr = new ImageAttributes();
     4 
     5             ColorMap colorMap = new ColorMap();
     6             colorMap.OldColor = Color.FromArgb( 25502550 );
     7             colorMap.NewColor = Color.FromArgb( 0000 );
     8             ColorMap[] remapTable = { colorMap };
     9 
    10             imgAttr.SetRemapTable( remapTable, ColorAdjustType.Bitmap );
    11 
    12             float[][] colorMatrixElements = { 
    13                new float[] {1.0f,  0.0f,  0.0f,  0.0f0.0f},
    14                new float[] {0.0f,  1.0f,  0.0f,  0.0f0.0f},
    15                new float[] {0.0f,  0.0f,  1.0f,  0.0f0.0f},
    16                new float[] {0.0f,  0.0f,  0.0f,  0.3f0.0f},
    17                new float[] {0.0f,  0.0f,  0.0f,  0.0f1.0f}
    18             };
    19 
    20             ColorMatrix wmColorMatrix = new ColorMatrix( colorMatrixElements );
    21             imgAttr.SetColorMatrix( wmColorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap );
    22 
    23             return imgAttr;
    24         }

    水印绘制的地方,也没有必要贴全部代码了

    1             ImageAttributes imgAttr = getImageAttributes();
    2             Rectangle rect = getPicPoint( src, wm, wp );
    3 
    4             g.DrawImage( wm, rect, 00, wm.Width, wm.Height, GraphicsUnit.Pixel, imgAttr );

    第一行,取得刚才那个变换规则

    第二行,取得绘制水印的矩形:我们可以指定水印的位置,比如左上角,右下角等等。通过位置的指定,获得不同的绘制区域的矩形。不过,getPicPoint 这个方法名称不好,让人误以为返回一个Point对象,其实是一个矩阵对象。建议换为getPicPosition或者getPicRect

    第三行就是绘制,在指定地方,使用指定颜色变换,绘制指定图片。

    绘制水印文字就相当简单了,使用一个透明的笔刷在图片上绘制水印即可。

      FontAndSize fs = FontAndSize.GetValue( g, words, "arial", fontSize, src.Width );
      PointF p 
    = getTextPoint( src, fs.size, wp );
      StringFormat sf 
    = getStringFormat();

      drawText( g, words, fs.font, p, sf );

    当然,这里我记录用了两种颜色绘制出文字,达到具有阴影效果文字特效。可以看出作者非常用心在开发我记录啊。。。。

    1         private static void drawText( Graphics g, String wmText, Font font, PointF p, StringFormat format ) {
    2 
    3             SolidBrush brush = new SolidBrush( Color.FromArgb( 153255255255 ) );
    4             g.DrawString( wmText, font, brush, p, format );
    5 
    6             SolidBrush brush2 = new SolidBrush( Color.FromArgb( 153000 ) );
    7             g.DrawString( wmText, font, brush2, new PointF( p.X + 1, p.Y + 1 ), format );
    8         }

    当然,代码里面的注释太少了,可能是非核心类,所以没有注释。当然,我们会在以后逐渐把注释补足的。作为一个服务大众的项目,注释是不能缺少的,让每个人看得懂的代码,是我们的目标。

    验证码的制作在 wojilu\Drawing\ValidationCode.cs

    验证码的制作可以分为3个步骤

    1.绘制一个带有噪点的背景

    2.绘制验证码

    3.最上层再绘制一些噪点

     1         public Image CreateImage( String code, int width, int height, String fontFamily ) {
     2 
     3             Bitmap bm = new Bitmap( width, height );
     4 
     5             using (Graphics g = Graphics.FromImage( bm )) {
     6 
     7                 g.SmoothingMode = SmoothingMode.AntiAlias;
     8 
     9                 HatchBrush brush = new HatchBrush( HatchStyle.SmallConfetti, Color.LightGray, Color.White );
    10                 Rectangle rect = new Rectangle( 00, width, height );
    11                 g.FillRectangle( brush, rect );
    12 
    13                 int fontsize = rect.Height + 1;
    14                 FontAndSize size = FontAndSize.GetValue( g, code, fontFamily, fontsize, bm.Width );
    15 
    16                 GraphicsPath gpath = getGraphicsPath( code, size.font, rect );
    17 
    18                 Color brushColor = ColorTranslator.FromHtml( "#000000" );
    19                 brush = new HatchBrush( HatchStyle.Divot, brushColor, Color.DarkGray );
    20                 g.FillPath( brush, gpath );
    21 
    22                 addRandomNoise( g, rect );
    23 
    24             }
    25             return bm;
    26         }
    27 
    28         private void addRandomNoise( Graphics g, Rectangle rect ) {
    29 
    30             HatchBrush brush = new HatchBrush( HatchStyle.Weave, Color.LightGray, Color.White );
    31 
    32             int m = Math.Max( rect.Width, rect.Height );
    33             for (int i = 0; i < (int)(rect.Width * rect.Height / 30F); i++) {
    34                 int x = rd.Next( rect.Width );
    35                 int y = rd.Next( rect.Height );
    36                 g.FillEllipse( brush, x, y, 23 );
    37             }
    38         }

          这里使用的是一个比较特别的笔刷HatchBrush,这个笔刷可以绘制出一些比较特别的效果,例如绘制验证码背景时候用到的HatchStyle.SmallConfetti ,绘制最上层噪点用的HatchStyle.Weave。灵活运用这些花纹的话,可以绘制出各种效果的验证码。当然wojilu的源代码并不是没有任何问题的,毕竟只有一个人在开发。这里的m这个变量看不出什么意义。

    关于我记录系统的验证码,已经做了很好的封装了,您可以直接使用,具体的使用方法参见官网文档:

    http://www.wojilu.com/Common/Page/71

    MSDN参考:

    ImageAttributes:

    http://msdn.microsoft.com/zh-cn/library/system.drawing.imaging.imageattributes.aspx

    ImageAttributes.SetRemapTable:

    http://msdn.microsoft.com/zh-cn/library/system.drawing.imaging.imageattributes.setremaptable.aspx

    ColorMatrix :

    http://msdn.microsoft.com/en-us/library/system.drawing.imaging.colormatrix.aspx

    我记录网址 http://www.wojilu.com/

    欢迎大家加入我记录开发团队

  • 相关阅读:
    两数之和
    IntelliJ IDEA为类和方法自动添加注释
    IDEA main 函数的快捷键
    Mac终端开启代理
    Pycharm节能模式
    使用正则表达式替换构造字典
    使用代理爬取微信文章
    利用 Scrapy 爬取知乎用户信息
    Scrapy选择器的用法
    Scrapy命令行基本用法
  • 原文地址:https://www.cnblogs.com/TextEditor/p/2078606.html
Copyright © 2011-2022 走看看