GDI+中常见的几个问题(11)

我在前面几章里面提到过ColorMatrix,可以将图像的色彩进行仿射变换。但是如果要对图 像的色彩进行非线性变换的话,那就必须用到更强悍的API了。在Windows早期,有一套标准 的色彩管理的API,叫做ICM 2.0 (Image Color Management 2.0)。在Windows Vista 以后, 这套API升级成了WCS 1.0 (Windows Color System 1.0)。 这套API实现了www.color.org 上说的色彩管理的算法,具体的内容在http://msdn.microsoft.com/en- us/library/dd372446(VS.85).aspx。其中包括了显示,设备以及Gamut影射的算法。

刚才顺手抄了一个使用ICM 2.0转换图像的算法,用C#把ICM的几个API 封装了一下,这样 就可以使用ICC来转换不同的图像了。

1 using System;
2 using System.Collections.Generic;
3 using System.Text;
4 using System.Runtime.InteropServices;
5 using System.Drawing;
6 using System.Drawing.Imaging;
7 using System.IO;
8
9 namespace ICCConverter
10 {
11     public class ICM
12     {
13         #region Consts
14
15          const uint PROFILE_FILENAME = 1; // profile data is NULL terminated filename
16         const uint PROFILE_READ = 1; // opened for read access
17         const uint FILE_SHARE_READ = 0x00000001;
18          const uint OPEN_EXISTING = 3;
19         const uint PROOF_MODE = 0x00000001;
20         const uint NORMAL_MODE = 0x00000002;
21         const uint BEST_MODE = 0x00000003;
22          const uint ENABLE_GAMUT_CHECKING = 0x00010000;
23         const uint USE_RELATIVE_COLORIMETRIC = 0x00020000;
24         const uint FAST_TRANSLATE = 0x00040000;
25         const int LCS_SIGNATURE = 0x50534F43; /* PSOC */
26
27         #endregion
28
29          #region Types
30
31         public enum BMFORMAT
32          {
33             //
34             // 16bpp - 5 bits per channel. The most significant bit is ignored.
35              //
36
37             BM_x555RGB = 0x0000,
38              BM_x555XYZ = 0x0101,
39             BM_x555Yxy,
40             BM_x555Lab,
41              BM_x555G3CH,
42
43             //
44              // Packed 8 bits per channel => 8bpp for GRAY and
45              // 24bpp for the 3 channel colors, more for hifi channels
46              //
47
48             BM_RGBTRIPLETS = 0x0002,
49             BM_BGRTRIPLETS = 0x0004,
50              BM_XYZTRIPLETS = 0x0201,
51             BM_YxyTRIPLETS,
52             BM_LabTRIPLETS,
53              BM_G3CHTRIPLETS,
54             BM_5CHANNEL,
55              BM_6CHANNEL,
56             BM_7CHANNEL,
57             BM_8CHANNEL,
58              BM_GRAY,
59
60             //
61              // 32bpp - 8 bits per channel. The most significant byte is ignored
62              // for the 3 channel colors.
63             //
64
65             BM_xRGBQUADS = 0x0008,
66              BM_xBGRQUADS = 0x0010,
67             BM_xG3CHQUADS = 0x0304,
68             BM_KYMCQUADS,
69             BM_CMYKQUADS = 0x0020,
70
71             //
72              // 32bpp - 10 bits per channel. The 2 most significant bits are ignored.
73             //
74
75             BM_10b_RGB = 0x0009,
76             BM_10b_XYZ = 0x0401,
77              BM_10b_Yxy,
78             BM_10b_Lab,
79              BM_10b_G3CH,
80
81             //
82             // 32bpp - named color indices (1-based)
83              //
84
85             BM_NAMED_INDEX,
86
87             //
88              // Packed 16 bits per channel => 16bpp for GRAY and
89              // 48bpp for the 3 channel colors.
90             //
91
92             BM_16b_RGB = 0x000A,
93              BM_16b_XYZ = 0x0501,
94             BM_16b_Yxy,
95              BM_16b_Lab,
96             BM_16b_G3CH,
97              BM_16b_GRAY,
98
99             //
100             // 16 bpp - 5 bits for Red & Blue, 6 bits for Green
101             //
102
103             BM_565RGB = 0x0001,
104
105             //#if NTDDI_VERSION >= NTDDI_LONGHORN
106             //
107              // scRGB - 32 bits per channel floating point
108             //         16 bits per channel floating point
109              //
110
111             BM_32b_scRGB = 0x0601,
112              BM_32b_scARGB = 0x0602,
113             BM_S2DOT13FIXED_scRGB = 0x0603,
114             BM_S2DOT13FIXED_scARGB = 0x0604
115             //#endif // NTDDI_VERSION >= NTDDI_LONGHORN
116
117         }
118
119          [StructLayout(LayoutKind.Sequential)]
120         public struct CIEXYZ
121         {
122             public int ciexyzX, ciexyzY, ciexyzZ;
123         }
124
125          [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
126          public struct tagPROFILE
127         {
128              public uint dwType;
129             public string pProfileData;
130             public uint cbDataSize;
131          }
132
133         [StructLayout(LayoutKind.Sequential)]
134         public struct CIEXYZTRIPLE
135         {
136             public CIEXYZ ciexyzRed, ciexyzGreen, ciexyBlue;
137         }
138
139         [StructLayout (LayoutKind.Sequential, CharSet = CharSet.Unicode)]
140         struct LOGCOLORSPACE
141         {
142             public uint Signature, Version, Size;
143             public int CSType, Intent, GammaRed, GammaGreen, GammaBlue;
144             public CIEXYZTRIPLE Endpoints;
145
146             [MarshalAs (UnmanagedType.ByValTStr, SizeConst = 260)]
147             public string Filename;
148         }
149
150         public enum GamutMappingIntent
151         {
152             LCS_GM_ABS_COLORIMETRIC = 0x00000008,
153             LCS_GM_BUSINESS = 0x00000001,
154             LCS_GM_GRAPHICS = 0x00000002,
155             LCS_GM_IMAGES = 0x00000004
156          }
157
158         public enum LogicalColorSpace
159          {
160             LCS_CALIBRATED_RGB = 0x00000000,
161             LCS_sRGB = 0x73524742,
162              LCS_WINDOWS_COLOR_SPACE = 0x57696E20
163         }
164
165
166
167         #endregion
168
169          public delegate bool ICMProgressProcCallback(uint ulMax, uint ulCurrent, int ulCallbackData);
170
171         [DllImport("mscms.dll", SetLastError = true)]
172         static extern IntPtr OpenColorProfile(ref tagPROFILE pProfile, uint AccessMode, uint ShareMode, uint CreateMode);
173
174
175
176         [DllImport("mscms.dll", SetLastError = true)]
177         static extern bool TranslateBitmapBits(IntPtr pTransform, IntPtr inBuffer, BMFORMAT inFormat, uint width, uint height, uint stride, IntPtr outBuffer, BMFORMAT outFormat, uint outStride, ICMProgressProcCallback pfCallback, int CallBackParam);
178
179          [DllImport("mscms.dll", SetLastError = true)]
180          static extern bool CloseColorProfile(IntPtr profile);
181
182          [DllImport("mscms.dll", SetLastError = true)]
183         static extern bool DeleteColorTransform(IntPtr transform);
184
185          [DllImport("mscms.dll", SetLastError = true)]
186         static extern IntPtr CreateColorTransform(ref LOGCOLORSPACE pLogColorSpace, IntPtr hDestProfile, IntPtr hTargetProfile, uint dwFlags);
187
188          public void Convert(string profilePath, string imageFilePath, string outputPath)
189         {
190
191             LOGCOLORSPACE logColorSpace = new LOGCOLORSPACE();
192
193              logColorSpace.Signature = LCS_SIGNATURE; /* LCS_SIGNATURE */
194              logColorSpace.Intent = (int) GamutMappingIntent.LCS_GM_IMAGES; /* LCS_GM_IMAGES */
195              logColorSpace.Version = 0x0400;
196             logColorSpace.Size = (uint)Marshal.SizeOf(logColorSpace);
197              logColorSpace.CSType = (int)LogicalColorSpace.LCS_sRGB; /* LCS_sRGB */
198             IntPtr Destprofile;
199
200              tagPROFILE profile = new tagPROFILE();
201             profile.dwType = PROFILE_FILENAME;
202             profile.pProfileData = profilePath;
203             profile.cbDataSize = (uint)profile.pProfileData.Length + 1;
204              Destprofile = OpenColorProfile(ref profile, PROFILE_READ, FILE_SHARE_READ, OPEN_EXISTING);
205             IntPtr pTransforms = CreateColorTransform(ref logColorSpace, Destprofile, IntPtr.Zero, BEST_MODE);
206
207             if (pTransforms != IntPtr.Zero)
208             {
209                  FileStream fs = new FileStream(imageFilePath, FileMode.Open, FileAccess.Read);
210                 Bitmap bmpTemp = (Bitmap)Image.FromStream(fs, false, false);
211                  Bitmap bmp = new Bitmap(bmpTemp);
212                 fs.Close();
213                 bmpTemp.Dispose ();
214
215                 BitmapData bmData = bmp.LockBits(new Rectangle(0, 0, bmp.Width, bmp.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
216                 bool success = TranslateBitmapBits(
217                     pTransforms,
218                     bmData.Scan0,
219                      BMFORMAT.BM_RGBTRIPLETS,
220                      (uint)bmData.Width,
221                      (uint)bmData.Height,
222                      (uint)bmData.Stride,
223                     bmData.Scan0,
224                     BMFORMAT.BM_RGBTRIPLETS,
225                     (uint) bmData.Stride, null, 0);
226                
227                  bmp.UnlockBits(bmData);
228                  bmp.Save(outputPath, ImageFormat.Jpeg);
229                  CloseColorProfile(Destprofile);
230                 DeleteColorTransform(Destprofile);
231             }
232              else
233             {
234                  int errorCode = Marshal.GetLastWin32Error();
235                  throw new COMException("Error", errorCode);
236              }
237         }
238     }
239 }
240
241

这一章其实跟GDI+并没有什么太大的关系,不知道什么时候这些代码会直接放在.NET Framework Code里面,这样用起来就方便了。

时间: 2024-08-03 07:14:11

GDI+中常见的几个问题(11)的相关文章

GDI+中常见的几个问题(9)

今天来讲讲上个星期遗留下来的东西:ColorMatrix. 9. Color Matrix 图像的本质是什么?对不同的人来说这是不同的东西.在计算机的世界中,啥东西都是数 据,图像也是一种数据.从自然界的光变成计算机的数据,需要通过采样和量化的处理.图 像在计算机中,其实是一个二维数组,从数学上来说,这其实是一个矩阵.图像中的每一个 点都是个四维向量,也就是(R,G,B,A), 在RGBA色彩空间中,我们可以使用一个矩阵对每一 个点(R,G,B,A)作矩阵乘法运算,这样就可以对图像色彩进行变换.

GDI+中常见的几个问题(8)

哈哈,这个星期Heroes第八集终于出来了,我继续顺着上一节外传讲下去,修改颜色怎么 做. 8.1 使用原始的方法修改图像的RGB以及色调,饱和度和亮度 最简单的办法,很容易,就是用之前的LockBits,然后直接修改R,G,B的数值,具体的就 不多说了.在GDI+里面,Color有3个方法,分别是GetHue(), GetSaturation(), GetBrightness().它是图像的色调,饱和度和亮度.其中Hue取值为[0,360),表示当前颜色 在哪一个角度,Saturation和B

GDI+中常见的几个问题(7)

7. 多帧图像 为了赶上英雄第三季的播放日程,我决定一个星期出一集. 在第七集Heroes里面,Peter 的功能都被他老爸吸收掉了.所以我的这个系列的第七集来讲讲GDI+没完全实现的一部分功 能. 多帧图像是指在一幅图像中有多个帧,支持多帧图像的格式不多,只有TIFF和GIF.其他 格式都不能作为多帧图像存储.其中TIFF可以支持很多页,GIF动画也支持多帧.使用GDI+可 以生成多帧TIFF,却没办法实现GIF动画的生成,有可能是因为专利的缘故.首先让我们来看 看怎么样在生成多帧的TIFF图

GDI+中常见的几个问题(5)

6.透明,半透明和不透明 这是个大题目.在WinForm/WPF里面我们经常会看到一些关于透明的属性,比如Backcolor 里面可以选择Transparant, Form里面有一个叫Opacity的属性.都是和透明以及透明度相关 的.在其实是在GDI+应用层上的一些东西,在这里我就不讲了.主要从更基本的地方讲起, 其中还包括两块完全不同的内容. 6.1 Alpha 我们在上一讲中提到了PixelFormat,当时我们在LockBits的时候把PixelFormat设定成为 Format24bp

GDI+中常见的几个问题(3)

4. 为啥读个图那么慢? 一般来说,读图可以用以下几种方法: 1 public static Image FromFile(string filename); 2 public static Image FromFile(string filename, bool useEmbeddedColorManagement); 3 public static Bitmap FromHbitmap(IntPtr hbitmap); 4 public static Bitmap FromHbitmap (

GDI+中常见的几个问题(10)

10. Graphics的几个属性. 今天我来讲讲Graphics在DrawImage里的几个的属性. Graphics是GDI+里面的大拿,可以用来画线,画矩形,甚至可以用来画各种各样的材质. 通过不同的Pen,Brush来实现.具体的使用方法是所有想用GDI+的同学的基础,我就不详细讲 了,具体可以参考MSDN:http://msdn.microsoft.com/en-us/library/haxsc50a(VS.80).aspx .我主要来讲2个大家不太注意的属性. a.Graphics.

GDI+中常见的几个问题(6)

6.2 GIF GIF的全称是图像交换格式Graphics Interchange Format,是CompuServe公司在1987年创 建并使用的.这种格式使用8位索引值来表达一个像素,也就是说1个像素1个byte,最多可以 表示256种颜色.它使用LZW无损压缩算法来对图像进行压缩,之后这家公司又和几家其他的 公司发明了PNG文件格式,并被更广泛地应用在Web以及其他领域.GIF支持动画,可以保存数 个帧并不断地播放.关于动画的部分我们将会放到非常后面来讲,现在只谈谈GIF的透明. 在GI

GDI+中常见的几个问题(4)

5.读图是快了,处理怎么还是慢? GDI+的Bitmap类提供了两个罪恶的函数GetPixel, SetPixel,用来获取某个像素点的颜色 值.这个2个函数如果只调用一次两次也就罢了,万一我想把整张图片加红一点,用下面的代 码,我估计你等到黄花菜都凉了,还没有算完呢. 看看下面的代码是怎么写的. 1 FileStream fs = new FileStream(image, FileMode.Open, FileAccess.Read); 2 Image img = Image.FromStr

GDI+中常见的几个问题(1)

1.GDI+的前世今生 GDI+全称图形设备接口,Graphics Device Interface (GDI) ,他的爸爸叫做GDI, 用C写 的.Windows XP出来以后用C++重新写了一下,变成了GDI+.从.NET Framework 1.0开始, GDI+就被正式封装在了.NET Framework里面,并被广泛地应用到了所有和图形图像相关的程 序中.不幸的是,这个GDI+引入了微软有史以来最大的2个patch,造成了Microsoft IT, Support, Developer