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

6.2 GIF

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

在GIF文件的头部有一个调色板Palette,里面保存了颜色的信息。一般而言,如果对GIF进行LockBits的操作,只能把它lock成Format*bppIndexed,这样才不会导致前面调色板信息的丢失,在处理上也更方便一些。在调色板里面定义了透明的颜色,也就是说当实际数据为这个颜色时,那个位置的颜色为透明。让我们来看看Palette是怎么使用的。 顺便再说一句,GIF没有半透明,只支持完全透明或者不透明。此外,在一个调色板中,只有一种颜色可以设置为透明,这是GIF标准所决定的。

 

 1           public   static   unsafe   void  ConvertTransparancyGif( int  colorIndex,  string  baseFile,  string  outputFile)
 2          {
 3               using  (FileStream fs  =   new  FileStream(baseFile, FileMode.Open, FileAccess.Read))
 4              {
 5                  Bitmap img  =  (Bitmap)Image.FromStream(fs,  false false );
 6                   int  width  =  img.Width;
 7                   int  height  =  img.Height;
 8 
 9                  Bitmap resultbmp  =   new  Bitmap(width, height, PixelFormat.Format8bppIndexed);
10                  ColorPalette palette  =  resultbmp.Palette;
11                   int  n  =   0 ;
12                   foreach  (Color tc  in  img.Palette.Entries)
13                  {
14                      palette.Entries[n]  =  Color.FromArgb( 255 , tc);
15                      n ++ ;
16                  }
17 
18                  palette.Entries[colorIndex]  =  Color.FromArgb( 0 , palette.Entries[colorIndex]);
19                  resultbmp.Palette  =  palette;
20 
21                   // now to copy the actual bitmap data 
22                  BitmapData src  =  img.LockBits(
23                       new  Rectangle( 0 0 , width, height),
24                      ImageLockMode.ReadOnly,
25                      img.PixelFormat);
26 
27                  BitmapData dst  =  resultbmp.LockBits(
28                       new  Rectangle( 0 0 , width, height),
29                      ImageLockMode.WriteOnly,
30                      resultbmp.PixelFormat);
31 
32                   byte *  pSrc  =  ( byte * )src.Scan0.ToPointer();
33                   byte *  pDst  =  ( byte * )dst.Scan0.ToPointer();
34                   int  offset  =  src.Stride  -  width;
35 
36                   // steps through each pixel 
37                   for  ( int  y  =   0 ; y  <  height; y ++ )
38                  {
39                       for  ( int  x  =   0 ; x  <  width; x ++ )
40                      {
41                          pDst[ 0 =  pSrc[ 0 ];
42                          pDst ++ ;
43                          pSrc ++ ;
44                      }
45                      pDst  +=  offset;
46                      pSrc  +=  offset;
47                  }
48 
49                   // unlock the bitmaps 
50                  img.UnlockBits(src);
51                  resultbmp.UnlockBits(dst);
52 
53                  resultbmp.Save(outputFile, ImageFormat.Gif);
54 
55                  img.Dispose();
56                  resultbmp.Dispose();
57              } 
59          }

 

 

请注意,在这里,我读图的时候和我之前推荐的方法不同。 我没有创建一个新的Bitmap,这是因为在创建新的Bitmap的时候,调色板信息会完全丢失,所以Indexed的格式不可以随意进行复制,否则将造成信息的丢失。这也就是为什么当时我说这是一个土办法的原因。真正的好办法是复制那个流,而不是直接去复制Bitmap。不过那是看需求的。在创建一个带透明颜色的GIF的时候,只要创建一个调色板,就一切OK了。这比Alpha通道修正要简单。还可以参考KB 319061 http://support.microsoft.com/kb/319061/en-us


最后提一句,Bitmap类还提供了一个MakeTransparent方法用于设置透明颜色,不过只对PNG有效。

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