使用ColorMatrix进行颜色变换

今天准备做个水印图片系统,使用ColorMatrix对图片进行颜色处理.发现这个东西的使用比较麻烦,现将此总结下.

首先要明白,在GDI+中,Color的表示方式为ARGB的方式,也就是一个颜色对象有Alpha,Red,Green,Blue四个分量.
如果我们要改变整个图片的颜色怎么办呢?第一种方法就是对图片每个点的颜色进行转换,比如我想让图片的红色加重一点,那么我需要遍历全部像素,然后对每个像素的的颜色值进行计算.这个方法思路清晰简单,不过效率就实在不敢恭维了,因此,.GDI+中使用颜色变换都是基于ColorMatrix的,这儿的颜色表示和上面有点区别,上面使用(a,r,g,b)中,a,r,g,b的范围是0-255,但是在这儿a,r,g,b的范围是0-1,它使用一个5x5矩阵来表示颜色变换,为什么要使用5x5矩阵而不是4x4矩阵呢?官方的解释是:"可通过用 4×4 矩阵乘以这些颜色矢量将线性变换(旋转和缩放等)应用到颜色矢量中。但是,您不能使用 4×4 矩阵进行平移(非线性)。如果在每个颜色矢量中再添加一个虚拟的第 5 坐标(例如,数字 1),则可使用 5×5 矩阵应用任何组合形式的线性变换和平移。由线性变换组成的后跟平移的变换称为仿射变换。
那么,具体来说应如何变换呢?比如,我要将图片中每个像素的R值修改为255,那么我们可以使用的计算方法为"r*0 + 1",则对应矩阵为:
[0,0,0,0,0]
[0,1,0,0,0]
[0,0,1,0,0]
[0,0,0,1,0]
[1,0,0,0,1]
比如有一个点为[0.3,0.2,0.4,1]转换计算为:
                               [0,0,0,0,0]
                               [0,1,0.0,0]
[0.3,0.2,0.4,1,1] * [0,0,1,0,0]  = [1,0.2,0.4,1,1]
                               [0,0,0,1,0]
                               [1,0,0,0,1]
很显然得到了预期结果
那么我们再来看看我们这次需要的,对图片透明的修改,很显然是修改alpha值,比如有float alpha,则变换如下:
[1,0,0,0,0]
[0,1,0,0,0]
[0,0,1,0,0]
[0,0,0,alpha /(float)255,0]
[0,0,0,0,0]
则能完成变换.

最后贴上水印图片生成类代码:

C#代码
  1. using System;   
  2. using System.Collections.Generic;   
  3. using System.Text;   
  4. using System.IO;   
  5. using System.Drawing;   
  6. using System.Drawing.Imaging;   
  7.   
  8. namespace LImage.Library   
  9. {   
  10.     public class ImageWater : IWater   
  11.     {   
  12.         private string imagePath;   
  13.         private Image waterImage;   
  14.   
  15.         public override TreatmentType Type   
  16.         {   
  17.             get { return TreatmentType.ImageWater; }   
  18.         }   
  19.   
  20.         public string ImagePath   
  21.         {   
  22.             get { return imagePath; }   
  23.             set { imagePath = value; }   
  24.         }   
  25.   
  26.         public ImageWater()   
  27.         {   
  28.             imagePath = string.Empty;   
  29.             waterPoint = WaterPoint.Create(0, 0);   
  30.             waterImage = null;   
  31.             waterColor = Color.FromArgb(128, 255, 255, 255);   
  32.         }   
  33.   
  34.         public ImageWater(string path)   
  35.             : this()   
  36.         {   
  37.             imagePath = path;   
  38.         }   
  39.   
  40.         public ImageWater(string path, WaterPoint point)   
  41.             :this()   
  42.         {   
  43.             imagePath = path;   
  44.             waterPoint = point;   
  45.         }   
  46.   
  47.         public ImageWater(string imagePath, WaterPoint point, Color color)   
  48.             : this()   
  49.         {   
  50.             waterPoint = point;   
  51.             waterColor = color;   
  52.         }   
  53.   
  54.         public void LoadWaterImage()   
  55.         {   
  56.             if (!File.Exists(imagePath))   
  57.                 throw new Exception("找不到水印图片.");   
  58.             waterImage = null;   
  59.             try  
  60.             {   
  61.                 waterImage = Image.FromFile(imagePath);   
  62.             }   
  63.             catch  
  64.             {   
  65.                 throw new Exception("无法识别的图片格式.");   
  66.             }   
  67.         }   
  68.   
  69.         public override void Treatment(string path)   
  70.         {   
  71.             if (waterImage == null)   
  72.                 LoadWaterImage();   
  73.             if (!File.Exists(path))   
  74.                 throw new Exception(string.Format("图片{0}不存在或者已经被删除.", path));   
  75.             Image image = null;   
  76.             FileStream fs = new FileStream(path, FileMode.Open, FileAccess.Read);   
  77.             try  
  78.             {   
  79.                 image = Image.FromStream(fs);   
  80.             }   
  81.             catch  
  82.             {   
  83.                 throw new Exception("不可识别的图片格式.");   
  84.             }   
  85.             finally  
  86.             {   
  87.                 fs.Close();   
  88.             }   
  89.             Graphics imageG = Graphics.FromImage(image);   
  90.             SolidBrush brush = new SolidBrush(waterColor);   
  91.             float px, py;   
  92.             switch (waterPoint.Type)   
  93.             {   
  94.                 case WaterPoint.PointType.LeftTop:   
  95.                 default:   
  96.                     px = waterPoint.x;   
  97.                     py = waterPoint.y;   
  98.                     break;   
  99.                 case WaterPoint.PointType.LeftBottom:   
  100.                     px = waterPoint.x;   
  101.                     py = image.Height - waterPoint.y - waterImage.Height;   
  102.                     break;   
  103.                 case WaterPoint.PointType.RightTop:   
  104.                     px = image.Width - waterPoint.x - waterImage.Width;   
  105.                     py = waterPoint.y;   
  106.                     break;   
  107.                 case WaterPoint.PointType.RightBottom:   
  108.                     px = image.Width - waterPoint.x -  waterImage.Width;   
  109.                     py = image.Height - waterPoint.y - waterImage.Height;   
  110.                     break;   
  111.             }   
  112.             if (px < 0)   
  113.                 px = 0;   
  114.             if (py < 0)   
  115.                 py = 0;   
  116.             addWatermarkImage(imageG, (int)px, (int)py);   
  117.             imageG.Save();   
  118.             fs = new FileStream(path, FileMode.Create, FileAccess.Write);   
  119.             Bitmap bitmap = new Bitmap(image);   
  120.             bitmap.Save(fs, image.RawFormat);   
  121.             //image.Save(fs, ImageFormat.Jpeg);   
  122.             fs.Close();   
  123.         }   
  124.   
  125.         private void addWatermarkImage(Graphics picture, int px, int py)   
  126.         {   
  127.             ImageAttributes imageAttributes = new ImageAttributes();   
  128.             ColorMap colorMap = new ColorMap();   
  129.             float af = waterColor.A / (float)255;   
  130.             ColorMap[] remapTable = { colorMap };   
  131.             imageAttributes.SetRemapTable(remapTable, ColorAdjustType.Bitmap);   
  132.             float[][] colorMatrixElements = {   
  133.                 new float[] {1.0f, 0.0f, 0.0f, 0.0f, 0.0f},   
  134.                 new float[] {0.0f, 1.0f, 0.0f, 0.0f, 0.0f},   
  135.                 new float[] {0.0f, 0.0f, 1.0f, 0.0f, 0.0f},   
  136.                 new float[] {0.0f, 0.0f, 0.0f, af, 0.0f},   
  137.                 new float[] {0.0f, 0.0f, 0.0f, 0.0f, 1.0f}   
  138.             };   
  139.             ColorMatrix colorMatrix = new ColorMatrix(colorMatrixElements);   
  140.             imageAttributes.SetColorMatrix(colorMatrix, ColorMatrixFlag.Default, ColorAdjustType.Bitmap);   
  141.             picture.DrawImage(waterImage, new Rectangle(px, py, waterImage.Width, waterImage.Height), 0, 0, waterImage.Width, waterImage.Height, GraphicsUnit.Pixel, imageAttributes);   
  142.             imageAttributes.Dispose();   
  143.         }   
  144.     }   
  145. }   
文章来自: 本站原创
引用通告: 查看所有引用 | 我要引用此文章
Tags: C#  ColorMatrix  颜色  变换 
评论: 0 | 引用: 0 | 查看次数: 581
发表评论
用户名:
密 码: 游客发言不需要密码.
验证码: 验证码
内 容:
选 项:
虽然发表评论不用注册,但是为了保护您的发言权,建议您注册帐号.
字数限制 500 字 | HTML代码允许 关闭 | 评论可修改 关闭