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

好久没有写了,真是灰常地惭愧。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,  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里面,这样用起来就方便了。

你可能感兴趣的:(GDI+中常见的几个问题(11))