Hotcan

享受生活的点点滴滴

  博客园 :: 首页 :: 博问 :: 闪存 :: 新随笔 :: 联系 :: 订阅 订阅 :: 管理 ::

好久没有写了,真是灰常地惭愧。Heroes都已经放到第24集了,而我只写到第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, falsefalse);
211                 Bitmap bmp = new Bitmap(bmpTemp);
212                 fs.Close();
213                 bmpTemp.Dispose();
214 
215                 BitmapData bmData = bmp.LockBits(new Rectangle(00, 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, null0);
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里面,这样用起来就方便了。

posted on 2009-04-22 23:44  Hotcan  阅读(3460)  评论(3编辑  收藏  举报