C#中保存GIF文件后透明背景问题的一个解决方法

以前在用C#做网站保存缩略图的程序中发现,当保存为GIF文件类型时,原来的透明背景变成了黑色,当时由于赶时间,就统一用白色代替了背景,并用Jpeg格式存储,并没有深究。

  近来在网上查阅了许多资料,看到了两种解决方法:一种是在显示时设置透明背景色,GIF文件本身并不改变,另一种是不推荐使用的调用API的方法。将后一种I的VB源码用C#重写后,发现其中的调色板设置太少,转换效果不理想。

  重新到网上搜索关于调色板的资料,发现MSDN上的一篇《对 ASP.NET 图像的颜色量化(Quantization)进行优化》的文章。

http://www.microsoft.com/china/MSDN/library/archives/library/DNAspp/html/colorquant.asp

  将其中基于调色板量化的代码分离出来,透明背景色的图片保存成功。

  完整代码如下:

using  System;
using  System.Collections;
using  System.Drawing;
using  System.Drawing.Imaging;
using  System.Runtime.InteropServices;

namespace  WindwoodGif
... {
    
public class GifPalette
    
...{
        
private static ArrayList _cardPalette;
        
private Color[] _colors;
        
private Hashtable _colorMap;

        
public GifPalette(ArrayList palette)
        
...{
            _colorMap 
= new Hashtable();
            _colors 
= new Color[palette.Count];
            palette.CopyTo(_colors);
        }


        
public GifPalette()
        
...{
            ArrayList palette 
= SetPalette();
            _colorMap 
= new Hashtable();
            _colors 
= new Color[palette.Count];
            palette.CopyTo(_colors);
        }


        
public Bitmap Quantize(Image source)
        
...{
            
int height = source.Height;
            
int width = source.Width;

            Rectangle bounds 
= new Rectangle(00, width, height);

            Bitmap copy 
= new Bitmap(width, height, PixelFormat.Format32bppArgb);
            Bitmap output 
= new Bitmap(width, height, PixelFormat.Format8bppIndexed);

            
using (Graphics g = Graphics.FromImage(copy))
            
...{
                g.PageUnit 
= GraphicsUnit.Pixel;

                g.DrawImageUnscaled(source, bounds);
            }


            BitmapData sourceData 
= null;

            
try
            
...{
                sourceData 
= copy.LockBits(bounds, ImageLockMode.ReadOnly, PixelFormat.Format32bppArgb);

                output.Palette 
= this.GetPalette(output.Palette);

                SecondPass(sourceData, output, width, height, bounds);
            }

            
finally
            
...{
                copy.UnlockBits(sourceData);
            }


            
return output;
        }


        
private ColorPalette GetPalette(ColorPalette palette)
        
...{
            
for (int index = 0; index < _colors.Length; index++)
                palette.Entries[index] 
= _colors[index];
            
return palette;
        }


        
private unsafe void SecondPass(BitmapData sourceData, Bitmap output, int width, int height, Rectangle bounds)
        
...{
            BitmapData outputData 
= null;

            
try
            
...{
                outputData 
= output.LockBits(bounds, ImageLockMode.WriteOnly, PixelFormat.Format8bppIndexed);

                
byte* pSourceRow = (byte*)sourceData.Scan0.ToPointer();
                Int32
* pSourcePixel = (Int32*)pSourceRow;
                Int32
* pPreviousPixel = pSourcePixel;

                
byte* pDestinationRow = (byte*)outputData.Scan0.ToPointer();
                
byte* pDestinationPixel = pDestinationRow;

                
byte pixelValue = QuantizePixel((Color32*)pSourcePixel);

                
*pDestinationPixel = pixelValue;

                
for (int row = 0; row < height; row++)
                
...{
                    pSourcePixel 
= (Int32*)pSourceRow;

                    pDestinationPixel 
= pDestinationRow;

                    
for (int col = 0; col < width; col++, pSourcePixel++, pDestinationPixel++)
                    
...{
                        
if (*pPreviousPixel != *pSourcePixel)
                        
...{
                            pixelValue 
= QuantizePixel((Color32*)pSourcePixel);

                            pPreviousPixel 
= pSourcePixel;
                        }


                        
*pDestinationPixel = pixelValue;
                    }


                    pSourceRow 
+= sourceData.Stride;

                    pDestinationRow 
+= outputData.Stride;
                }

            }

            
finally
            
...{
                output.UnlockBits(outputData);
            }

        }


        
private unsafe byte QuantizePixel(Color32* pixel)
        
...{
            
byte colorIndex = 0;
            
int colorHash = pixel->ARGB;

            
if (_colorMap.ContainsKey(colorHash))
                colorIndex 
= (byte)_colorMap[colorHash];
            
else
            
...{
                
if (0 == pixel->Alpha)
                
...{
                    
for (int index = 0; index < _colors.Length; index++)
                    
...{
                        
if (0 == _colors[index].A)
                        
...{
                            colorIndex 
= (byte)index;
                            
break;
                        }

                    }

                }

                
else
                
...{
                    
int leastDistance = int.MaxValue;
                    
int red = pixel->Red;
                    
int green = pixel->Green;
                    
int blue = pixel->Blue;

                    
for (int index = 0; index < _colors.Length; index++)
                    
...{
                        Color paletteColor 
= _colors[index];

                        
int redDistance = paletteColor.R - red;
                        
int greenDistance = paletteColor.G - green;
                        
int blueDistance = paletteColor.B - blue;

                        
int distance = (redDistance * redDistance) +
                                           (greenDistance 
* greenDistance) +
                                           (blueDistance 
* blueDistance);

                        
if (distance < leastDistance)
                        
...{
                            colorIndex 
= (byte)index;
                            leastDistance 
= distance;

                            
if (0 == distance)
                                
break;
                        }

                    }

                }


                _colorMap.Add(colorHash, colorIndex);
            }


            
return colorIndex;
        }


        [StructLayout(LayoutKind.Explicit)]
        
public struct Color32
        
...{
            [FieldOffset(
0)]
            
public byte Blue;

            [FieldOffset(
1)]
            
public byte Green;

            [FieldOffset(
2)]
            
public byte Red;

            [FieldOffset(
3)]
            
public byte Alpha;

            [FieldOffset(
0)]
            
public int ARGB;

            
public Color Color
            
...{
                
get ...return Color.FromArgb(Alpha, Red, Green, Blue); }
            }

        }


        
public static ArrayList SetPalette()
        
...{
            
if (null == _cardPalette)
            
...{
                _cardPalette 
= new ArrayList();

                
Insert the colors into the arraylist#region Insert the colors into the arraylist
                _cardPalette.Add(Color.FromArgb(
255000));
                _cardPalette.Add(Color.FromArgb(
25512800));
                _cardPalette.Add(Color.FromArgb(
25501280));
                _cardPalette.Add(Color.FromArgb(
2551281280));
                _cardPalette.Add(Color.FromArgb(
25500128));
                _cardPalette.Add(Color.FromArgb(
2551280128));
                _cardPalette.Add(Color.FromArgb(
2550128128));
                _cardPalette.Add(Color.FromArgb(
255192192192));
                _cardPalette.Add(Color.FromArgb(
255192220192));
                _cardPalette.Add(Color.FromArgb(
255166202240));
                _cardPalette.Add(Color.FromArgb(
25512583));
                _cardPalette.Add(Color.FromArgb(
25513792));
                _cardPalette.Add(Color.FromArgb(
255251103));
                _cardPalette.Add(Color.FromArgb(
2551866114));
                _cardPalette.Add(Color.FromArgb(
2553978123));
                _cardPalette.Add(Color.FromArgb(
25510163107));
                _cardPalette.Add(Color.FromArgb(
2557292119));
                _cardPalette.Add(Color.FromArgb(
2558974121));
                _cardPalette.Add(Color.FromArgb(
25585101122));
                _cardPalette.Add(Color.FromArgb(
25512289127));
                _cardPalette.Add(Color.FromArgb(
255101108106));
                _cardPalette.Add(Color.FromArgb(
255111116111));
                _cardPalette.Add(Color.FromArgb(
255109118122));
                _cardPalette.Add(Color.FromArgb(
25512011997));
                _cardPalette.Add(Color.FromArgb(
255121124114));
                _cardPalette.Add(Color.FromArgb(
255152154));
                _cardPalette.Add(Color.FromArgb(
2551661156));
                _cardPalette.Add(Color.FromArgb(
2551563160));
                _cardPalette.Add(Color.FromArgb(
2553755131));
                _cardPalette.Add(Color.FromArgb(
2552469158));
                _cardPalette.Add(Color.FromArgb(
2552168162));
                _cardPalette.Add(Color.FromArgb(
2553571137));
                _cardPalette.Add(Color.FromArgb(
2553371152));
                _cardPalette.Add(Color.FromArgb(
2554393130));
                _cardPalette.Add(Color.FromArgb(
2555168139));
                _cardPalette.Add(Color.FromArgb(
2554879159));
                _cardPalette.Add(Color.FromArgb(
2555385131));
                _cardPalette.Add(Color.FromArgb(
2554981151));
                _cardPalette.Add(Color.FromArgb(
2553478167));
                _cardPalette.Add(Color.FromArgb(
2554184170));
                _cardPalette.Add(Color.FromArgb(
2555091173));
                _cardPalette.Add(Color.FromArgb(
2555494176));
                _cardPalette.Add(Color.FromArgb(
25553101136));
                _cardPalette.Add(Color.FromArgb(
2556097168));
                _cardPalette.Add(Color.FromArgb(
2555999177));
                _cardPalette.Add(Color.FromArgb(
2556893134));
                _cardPalette.Add(Color.FromArgb(
2556791150));
                _cardPalette.Add(Color.FromArgb(
2558693151));
                _cardPalette.Add(Color.FromArgb(
25564102142));
                _cardPalette.Add(Color.FromArgb(
25576105153));
                _cardPalette.Add(Color.FromArgb(
25575116150));
                _cardPalette.Add(Color.FromArgb(
25581103140));
                _cardPalette.Add(Color.FromArgb(
25584106147));
                _cardPalette.Add(Color.FromArgb(
25591113146));
                _cardPalette.Add(Color.FromArgb(
25575107172));
                _cardPalette.Add(Color.FromArgb(
25565103180));
                _cardPalette.Add(Color.FromArgb(
25577113184));
                _cardPalette.Add(Color.FromArgb(
25590104162));
                _cardPalette.Add(Color.FromArgb(
25590115160));
                _cardPalette.Add(Color.FromArgb(
25590123189));
                _cardPalette.Add(Color.FromArgb(
25510187130));
                _cardPalette.Add(Color.FromArgb(
255106108158));
                _cardPalette.Add(Color.FromArgb(
255101115130));
                _cardPalette.Add(Color.FromArgb(
255103121149));
                _cardPalette.Add(Color.FromArgb(
25511299139));
                _cardPalette.Add(Color.FromArgb(
255122110148));
                _cardPalette.Add(Color.FromArgb(
255101122165));
                _cardPalette.Add(Color.FromArgb(
255116124172));
                _cardPalette.Add(Color.FromArgb(
25593126192));
                _cardPalette.Add(Color.FromArgb(
25596127192));
                _cardPalette.Add(Color.FromArgb(
07225442));
                _cardPalette.Add(Color.FromArgb(
25590128160));
                _cardPalette.Add(Color.FromArgb(
25597130159));
                _cardPalette.Add(Color.FromArgb(
255119129138));
                _cardPalette.Add(Color.FromArgb(
255118133154));
                _cardPalette.Add(Color.FromArgb(
255107131169));
                _cardPalette.Add(Color.FromArgb(
255105132186));
                _cardPalette.Add(Color.FromArgb(
255118138170));
                _cardPalette.Add(Color.FromArgb(
255117137180));
                _cardPalette.Add(Color.FromArgb(
255118145173));
                _cardPalette.Add(Color.FromArgb(
255124152183));
                _cardPalette.Add(Color.FromArgb(
25595128192));
                _cardPalette.Add(Color.FromArgb(
255102133195));
                _cardPalette.Add(Color.FromArgb(
255112141199));
                _cardPalette.Add(Color.FromArgb(
255120147202));
                _cardPalette.Add(Color.FromArgb(
2551545353));
                _cardPalette.Add(Color.FromArgb(
2551317291));
                _cardPalette.Add(Color.FromArgb(
25514387104));
                _cardPalette.Add(Color.FromArgb(
25512912392));
                _cardPalette.Add(Color.FromArgb(
25515612468));
                _cardPalette.Add(Color.FromArgb(
255129126101));
                _cardPalette.Add(Color.FromArgb(
255154105120));
                _cardPalette.Add(Color.FromArgb(
2551698382));
                _cardPalette.Add(Color.FromArgb(
25516512570));
                _cardPalette.Add(Color.FromArgb(
25516012580));
                _cardPalette.Add(Color.FromArgb(
255176109114));
                _cardPalette.Add(Color.FromArgb(
255205532));
                _cardPalette.Add(Color.FromArgb(
2552096719));
                _cardPalette.Add(Color.FromArgb(
2552108547));
                _cardPalette.Add(Color.FromArgb(
2552306721));
                _cardPalette.Add(Color.FromArgb(
2552438846));
                _cardPalette.Add(Color.FromArgb(
2552559753));
                _cardPalette.Add(Color.FromArgb(
2552019271));
                _cardPalette.Add(Color.FromArgb(
25521410779));
                _cardPalette.Add(Color.FromArgb(
255205117105));
                _cardPalette.Add(Color.FromArgb(
25524511274));
                _cardPalette.Add(Color.FromArgb(
255131101136));
                _cardPalette.Add(Color.FromArgb(
255139110144));
                _cardPalette.Add(Color.FromArgb(
255130120156));
                _cardPalette.Add(Color.FromArgb(
255146124155));
                _cardPalette.Add(Color.FromArgb(
255162117131));
                _cardPalette.Add(Color.FromArgb(
25514113394));
                _cardPalette.Add(Color.FromArgb(
25515613172));
                _cardPalette.Add(Color.FromArgb(
25515113383));
                _cardPalette.Add(Color.FromArgb(
25515714492));
                _cardPalette.Add(Color.FromArgb(
255137132102));
                _cardPalette.Add(Color.FromArgb(
255135136120));
                _cardPalette.Add(Color.FromArgb(
255147139102));
                _cardPalette.Add(Color.FromArgb(
255148143115));
                _cardPalette.Add(Color.FromArgb(
255156146106));
                _cardPalette.Add(Color.FromArgb(
255148145122));
                _cardPalette.Add(Color.FromArgb(
25516813673));
                _cardPalette.Add(Color.FromArgb(
25516813888));
                _cardPalette.Add(Color.FromArgb(
25517214790));
                _cardPalette.Add(Color.FromArgb(
25517813882));
                _cardPalette.Add(Color.FromArgb(
25518615369));
                _cardPalette.Add(Color.FromArgb(
25517915091));
                _cardPalette.Add(Color.FromArgb(
255174139100));
                _cardPalette.Add(Color.FromArgb(
255166154107));
                _cardPalette.Add(Color.FromArgb(
255161151114));
                _cardPalette.Add(Color.FromArgb(
255182154101));
                _cardPalette.Add(Color.FromArgb(
25519016281));
                _cardPalette.Add(Color.FromArgb(
255172160117));
                _cardPalette.Add(Color.FromArgb(
255183161103));
                _cardPalette.Add(Color.FromArgb(
255182163119));
                _cardPalette.Add(Color.FromArgb(
25520516863));
                _cardPalette.Add(Color.FromArgb(
25521817452));
                _cardPalette.Add(Color.FromArgb(
25522117753));
                _cardPalette.Add(Color.FromArgb(
2552551541));
                _cardPalette.Add(Color.FromArgb(
25525516118));
                _cardPalette.Add(Color.FromArgb(
25523518444));
                _cardPalette.Add(Color.FromArgb(
25522818252));
                _cardPalette.Add(Color.FromArgb(
25524719036));
                _cardPalette.Add(Color.FromArgb(
25520015594));
                _cardPalette.Add(Color.FromArgb(
255192153104));
                _cardPalette.Add(Color.FromArgb(
255223130103));
                _cardPalette.Add(Color.FromArgb(
255215132118));
                _cardPalette.Add(Color.FromArgb(
25520116768));
                _cardPalette.Add(Color.FromArgb(
25519616787));
                _cardPalette.Add(Color.FromArgb(
25520917370));
                _cardPalette.Add(Color.FromArgb(
25521216991));
                _cardPalette.Add(Color.FromArgb(
25521317773));
                _cardPalette.Add(Color.FromArgb(
255198166102));
                _cardPalette.Add(Color.FromArgb(
255196168123));
                _cardPalette.Add(Color.FromArgb(
255219172112));
                _cardPalette.Add(Color.FromArgb(
255219183106));
                _cardPalette.Add(Color.FromArgb(
255217185115));
                _cardPalette.Add(Color.FromArgb(
25525513191));
                _cardPalette.Add(Color.FromArgb(
255249143109));
                _cardPalette.Add(Color.FromArgb(
255227186108));
                _cardPalette.Add(Color.FromArgb(
255229186112));
                _cardPalette.Add(Color.FromArgb(
255255164123));
                _cardPalette.Add(Color.FromArgb(
255207195127));
                _cardPalette.Add(Color.FromArgb(
25525320494));
                _cardPalette.Add(Color.FromArgb(
255235194108));
                _cardPalette.Add(Color.FromArgb(
255233197117));
                _cardPalette.Add(Color.FromArgb(
255252204104));
                _cardPalette.Add(Color.FromArgb(
255249204115));
                _cardPalette.Add(Color.FromArgb(
255251208106));
                _cardPalette.Add(Color.FromArgb(
255253209117));
                _cardPalette.Add(Color.FromArgb(
255128137140));
                _cardPalette.Add(Color.FromArgb(
255136144145));
                _cardPalette.Add(Color.FromArgb(
255151150130));
                _cardPalette.Add(Color.FromArgb(
255144149148));
                _cardPalette.Add(Color.FromArgb(
255137131165));
                _cardPalette.Add(Color.FromArgb(
255137140180));
                _cardPalette.Add(Color.FromArgb(
255140154168));
                _cardPalette.Add(Color.FromArgb(
255133151180));
                _cardPalette.Add(Color.FromArgb(
255149137167));
                _cardPalette.Add(Color.FromArgb(
255149152188));
                _cardPalette.Add(Color.FromArgb(
255138168188));
                _cardPalette.Add(Color.FromArgb(
255175135148));
                _cardPalette.Add(Color.FromArgb(
255169154129));
                _cardPalette.Add(Color.FromArgb(
255187135134));
                _cardPalette.Add(Color.FromArgb(
255178138148));
                _cardPalette.Add(Color.FromArgb(
255184146156));
                _cardPalette.Add(Color.FromArgb(
255168149173));
                _cardPalette.Add(Color.FromArgb(
255170163131));
                _cardPalette.Add(Color.FromArgb(
255184165128));
                _cardPalette.Add(Color.FromArgb(
255181166157));
                _cardPalette.Add(Color.FromArgb(
255162175186));
                _cardPalette.Add(Color.FromArgb(
255189185170));
                _cardPalette.Add(Color.FromArgb(
255130155206));
                _cardPalette.Add(Color.FromArgb(
255134158208));
                _cardPalette.Add(Color.FromArgb(
255146155196));
                _cardPalette.Add(Color.FromArgb(
255142169193));
                _cardPalette.Add(Color.FromArgb(
255140163209));
                _cardPalette.Add(Color.FromArgb(
255153168199));
                _cardPalette.Add(Color.FromArgb(
255148170213));
                _cardPalette.Add(Color.FromArgb(
255157177216));
                _cardPalette.Add(Color.FromArgb(
255164166193));
                _cardPalette.Add(Color.FromArgb(
255171179198));
                _cardPalette.Add(Color.FromArgb(
255167185220));
                _cardPalette.Add(Color.FromArgb(
255181179205));
                _cardPalette.Add(Color.FromArgb(
255181188211));
                _cardPalette.Add(Color.FromArgb(
255173190224));
                _cardPalette.Add(Color.FromArgb(
255178196217));
                _cardPalette.Add(Color.FromArgb(
255174192224));
                _cardPalette.Add(Color.FromArgb(
255174212224));
                _cardPalette.Add(Color.FromArgb(
255184198227));
                _cardPalette.Add(Color.FromArgb(
255185218229));
                _cardPalette.Add(Color.FromArgb(
255202145142));
                _cardPalette.Add(Color.FromArgb(
255196172134));
                _cardPalette.Add(Color.FromArgb(
255203161158));
                _cardPalette.Add(Color.FromArgb(
255203177134));
                _cardPalette.Add(Color.FromArgb(
255207185151));
                _cardPalette.Add(Color.FromArgb(
255210186132));
                _cardPalette.Add(Color.FromArgb(
255215189148));
                _cardPalette.Add(Color.FromArgb(
255213168167));
                _cardPalette.Add(Color.FromArgb(
255234155132));
                _cardPalette.Add(Color.FromArgb(
255253172140));
                _cardPalette.Add(Color.FromArgb(
255193191193));
                _cardPalette.Add(Color.FromArgb(
255206194135));
                _cardPalette.Add(Color.FromArgb(
255214198136));
                _cardPalette.Add(Color.FromArgb(
255219204145));
                _cardPalette.Add(Color.FromArgb(
255218209141));
                _cardPalette.Add(Color.FromArgb(
255215209154));
                _cardPalette.Add(Color.FromArgb(
255231196135));
                _cardPalette.Add(Color.FromArgb(
255225213143));
                _cardPalette.Add(Color.FromArgb(
255231217148));
                _cardPalette.Add(Color.FromArgb(
255251212129));
                _cardPalette.Add(Color.FromArgb(
255255199172));
                _cardPalette.Add(Color.FromArgb(
255202205219));
                _cardPalette.Add(Color.FromArgb(
255193205230));
                _cardPalette.Add(Color.FromArgb(
255200211233));
                _cardPalette.Add(Color.FromArgb(
255211220237));
                _cardPalette.Add(Color.FromArgb(
255213222240));
                _cardPalette.Add(Color.FromArgb(
255201226228));
                _cardPalette.Add(Color.FromArgb(
255201231242));
                _cardPalette.Add(Color.FromArgb(
255216227232));
                _cardPalette.Add(Color.FromArgb(
255219227241));
                _cardPalette.Add(Color.FromArgb(
255228233237));
                _cardPalette.Add(Color.FromArgb(
255229234244));
                _cardPalette.Add(Color.FromArgb(
255236241248));
                _cardPalette.Add(Color.FromArgb(
255240239243));
                _cardPalette.Add(Color.FromArgb(
255253253254));
                _cardPalette.Add(Color.FromArgb(
255255251240));
                _cardPalette.Add(Color.FromArgb(
255160160164));
                _cardPalette.Add(Color.FromArgb(
255128128128));
                _cardPalette.Add(Color.FromArgb(
25525500));
                _cardPalette.Add(Color.FromArgb(
25502550));
                _cardPalette.Add(Color.FromArgb(
2552552550));
                _cardPalette.Add(Color.FromArgb(
25500255));
                _cardPalette.Add(Color.FromArgb(
2552550255));
                _cardPalette.Add(Color.FromArgb(
2550255255));
                _cardPalette.Add(Color.FromArgb(
255255255255));
                
#endregion

            }

            
return _cardPalette;
        }


    }

}

  调用方法:

  先将该类添加到项目中,再在合适的地方调用。例:

        Bitmap bitmap = new System.Drawing.Bitmap(width, height);     // Image类也可
        // ......(图形操作代码)
        WindwoodGif.GifPalette gifPalette = new WindwoodGif.GifPalette();
        bitmap = gifPalette.Quantize(bitmap);
        bitmap.Save(SaveFileName, ImageFormat.Gif);

  经测试,这种方法能够实现GIF文件的透明背景存储,在WinForm、WebForm均能使用。由于使用了标准256色调色板,内存开销可能较大,转换时间相对较慢,图像质量也有一定影响。此外,代码中使用了非安全代码(指针),在编译时项目属性中要设置允许不安全代码。

转载于:https://www.cnblogs.com/zhy4606/archive/2008/01/04/1025588.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值