C# 实现GIF图片水印效果
之前自己试过GIF实现水印效果 最理想的一个是水印效果实现了 但是没有帧动画了 资质不行写不出来 所以在网上搜了下 codeproject 就是有能人啊 俺在这里借花献佛
主要有六个类 AnimatedGifEncoder Frame GifDecoder GifHelper LZWEncoder NeuQuant 有注释英文的 一看便知
Gif_Faster.rar
(258.55 KB)
例如:
程序代码:
using System; using System.Cousing System; using System.Drawing; using using System.Drawing.Imaging; #region .NET Disclaimer/Info //=============================================================================== // // gOODiDEA, //=============================================================================== // // $Header : $ // $Author : $ // $Date : $ // $Revision: $ // $History: $ // //=============================================================================== #endregion #region Java /** * Class AnimatedGifEncoder - Encodes a GIF file consisting of one or * more frames. * <pre> * Example: * AnimatedGifEncoder e = new AnimatedGifEncoder(); * e.start(outputFileName); * e.setDelay(1000); // 1 frame per sec * e.addFrame(image1); * e.addFrame(image2); * e.finish(); * </pre> * No copyright asserted on the source code of this class. May be used * for any purpose, however, refer to the Unisys LZW patent for restrictions * on use of the associated LZWEncoder class. Please forward any corrections * to kweiner@* * @author Kevin Weiner, FM Software * @version 1.03 November 2003 * */ #endregion namespace { public class AnimatedGifEncoder { protected int width; // image size protected int height; protected Color transparent = Color.Empty; // transparent color if given protected int transIndex; // transparent index in color table protected int repeat = -1; // no repeat protected int delay = 0; // frame delay (hundredths) protected bool started = false; // ready to output frames // protected BinaryWriter bw; protected FileStream fs; protected Image image; // current frame protected byte[] pixels; // BGR byte array from frame protected byte[] indexedPixels; // converted frame indexed to palette protected int colorDepth; // number of bit planes protected byte[] colorTab; // RGB palette protected bool[] usedEntry = new bool[256]; // active palette entries protected int palSize = 7; // color table size (bits-1) protected int dispose = -1; // disposal code (-1 = use default) protected bool closeStream = false; // close stream when finished protected bool firstFrame = true; protected bool sizeSet = false; // if false, get size from first frame protected int sample = 10; // default sample interval for quantizer /** * Sets the delay time between each frame, or changes it * for subsequent frames (applies to last frame added). * * @param ms int delay time in milliseconds */ public void SetDelay(int ms) { delay = ms;// (int)Math.Round(ms / 10.0f); } /** * Sets the GIF frame disposal code for the last added frame * and any subsequent frames. Default is 0 if no transparent * color has been set, otherwise 2. * @param code int disposal code. */ public void SetDispose(int code) { if (code >= 0) { dispose = code; } } /** * Sets the number of times the set of GIF frames * should be played. Default is 1; 0 means play * indefinitely. Must be invoked before the first * image is added. * * @param iter int number of iterations. * @return */ public void SetRepeat(int iter) { if (iter >= 0) { repeat = iter; } } /** * Sets the transparent color for the last added frame * and any subsequent frames. * Since all colors are subject to modification * in the quantization process, the color in the final * palette for each frame closest to the given color * becomes the transparent color for that frame. * May be set to null to indicate no transparent color. * * @param c Color to be treated as transparent on display. */ public void SetTransparent(Color c) { transparent = c; } /** * Adds next GIF frame. The frame is not written immediately, but is * actually deferred until the next frame is received so that timing * data can be inserted. Invoking <code>finish()</code> flushes all * frames. If <code>setSize</code> was not invoked, the size of the * first image is used for all subsequent frames. * * @param im BufferedImage containing frame to write. * @return true if successful. */ public bool AddFrame(Image im) { if ((im == null) || !started) { return false; } bool ok = true; try { if (!sizeSet) { // use first frame's size SetSize(im.Width, im.Height); } image = im; GetImagePixels(); // convert to correct format if necessary AnalyzePixels(); // build color table & map pixels if (firstFrame) { WriteLSD(); // logical screen descriptior WritePalette(); // global color table if (repeat >= 0) { // use NS app extension to indicate reps WriteNetscapeExt(); } } WriteGraphicCtrlExt(); // write graphic control extension WriteImageDesc(); // image descriptor if (!firstFrame) { WritePalette(); // local color table } WritePixels(); // encode and write pixel data firstFrame = false; } catch (IOException e) { ok = false; } return ok; } /** * Flushes any pending data and closes output file. * If writing to an OutputStream, the stream is not * closed. */ public bool Finish() { if (!started) return false; bool ok = true; started = false; try { fs.WriteByte( 0x3b ); // gif trailer fs.Flush(); if (closeStream) { fs.Close(); } } catch (IOException e) { ok = false; } // reset for subsequent use transIndex = 0; fs = null; image = null; pixels = null; indexedPixels = null; colorTab = null; closeStream = false; firstFrame = true; return ok; } /** * Sets frame rate in frames per second. Equivalent to * <code>setDelay(1000/fps)</code>. * * @param fps float frame rate (frames per second) */ public void SetFrameRate(float fps) { if (fps != 0f) { delay = ( int ) Math.Round(100f / fps); } } /** * Sets quality of color quantization (conversion of images * to the maximum 256 colors allowed by the GIF specification). * Lower values (minimum = 1) produce better colors, but slow * processing significantly. 10 is the default, and produces * good color mapping at reasonable speeds. Values greater * than 20 do not yield significant improvements in speed. * * @param quality int greater than 0. * @return */ public void SetQuality(int quality) { if (quality < 1) quality = 1; sample = quality; } /** * Sets the GIF frame size. The default size is the * size of the first frame added if this method is * not invoked. * * @param w int frame width. * @param h int frame width. */ public void SetSize(int w, int h) { if (started && !firstFrame) return; width = w; height = h; if (width < 1) width = 320; if (height < 1) height = 240; sizeSet = true; } /** * Initiates GIF file creation on the given stream. The stream * is not closed automatically. * * @param os OutputStream on which GIF images are written. * @return false if initial write failed. */ public bool Start( FileStream os) { if (os == null) return false; bool ok = true; closeStream = false; fs = os; try { WriteString("GIF89a"); // header } catch (IOException e) { ok = false; } return started = ok; } /** * Initiates writing of a GIF file with the specified name. * * @param file String containing output file name. * @return false if open or initial write failed. */ public bool Start(String file) { bool ok = true; try { // bw = new BinaryWriter( new FileStream( file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None ) ); fs = new FileStream( file, FileMode.OpenOrCreate, FileAccess.Write, FileShare.None ); ok = Start(fs); closeStream = true; } catch (IOException e) { ok = false; } return started = ok; } /** * Analyzes image colors and creates color map. */ protected void AnalyzePixels() { int len = pixels.Length; int nPix = len / 3; indexedPixels = new byte[nPix]; NeuQuant nq = new NeuQuant(pixels, len, sample); // initialize quantizer colorTab = nq.Process(); // create reduced palette // convert map from BGR to RGB // for (int i = 0; i < colorTab.Length; i += 3) // { // byte temp = colorTab[i]; // colorTab[i] = colorTab[i + 2]; // colorTab[i + 2] = temp; // usedEntry[i / 3] = false; // } // map image pixels to new palette int k = 0; for (int i = 0; i < nPix; i++) { int index = nq.Map(pixels[k++] & 0xff, pixels[k++] & 0xff, pixels[k++] & 0xff); usedEntry[index] = true; indexedPixels[i] = (byte) index; } pixels = null; colorDepth = 8; palSize = 7; // get closest match to transparent color if specified if (transparent != Color.Empty ) { transIndex = FindClosest(transparent); } } /** * Returns index of palette color closest to c * */ protected int FindClosest(Color c) { if (colorTab == null) return -1; int r = c.R; int g = c.G; int b = c.B; int minpos = 0; int dmin = 256 * 256 * 256; int len = colorTab.Length; for (int i = 0; i < len;) { int dr = r - (colorTab[i++] & 0xff); int dg = g - (colorTab[i++] & 0xff); int db = b - (colorTab[i] & 0xff); int d = dr * dr + dg * dg + db * db; int index = i / 3; if (usedEntry[index] && (d < dmin)) { dmin = d; minpos = index; } i++; } return minpos; } /** * Extracts image pixels into byte array "pixels" */ protected void GetImagePixels() { int w = image.Width; int h = image.Height; // int type = image.GetType().; if ((w != width) || (h != height) ) { // create new image with right size/format Image temp = new Bitmap(width, height ); Graphics g = Graphics.FromImage( temp ); g.DrawImage(image, 0, 0); image = temp; g.Dispose(); } /* ToDo: improve performance: use unsafe code */ pixels = new Byte [ 3 * image.Width * image.Height ]; int count = 0; Bitmap tempBitmap = new Bitmap( image ); int wh = image.Width; int he = image.Height; BitmapData bmpData = tempBitmap.LockBits(new Rectangle(0, 0, wh, he), ImageLockMode.ReadWrite, image.PixelFormat); unsafe { byte* p = (byte*)bmpData.Scan0.ToPointer(); for (int i = 0; i < 4 * wh * he; i += 4) { pixels[count] = *(p + i + 2); count++; pixels[count] = *(p + i + 1); count++; pixels[count] = *(p + i); count++; } } tempBitmap.UnlockBits(bmpData); //for (int th = 0; th < image.Height; th++) //{ // for (int tw = 0; tw < image.Width; tw++) // { // Color color = tempBitmap.GetPixel(tw, th); // pixels[count] = color.R; // count++; // pixels[count] = color.G; // count++; // pixels[count] = color.B; // count++; // } //} // pixels = ((DataBufferByte) image.getRaster().getDataBuffer()).getData(); } /** * Writes Graphic Control Extension */ protected void WriteGraphicCtrlExt() { fs.WriteByte(0x21); // extension introducer fs.WriteByte(0xf9); // GCE label fs.WriteByte(4); // data block size int transp, disp; if (transparent == Color.Empty ) { transp = 0; disp = 0; // dispose = no action } else { transp = 1; disp = 2; // force clear if using transparent color } if (dispose >= 0) { disp = dispose & 7; // user override } disp <<= 2; // packed fields fs.WriteByte( Convert.ToByte( 0 | // 1:3 reserved disp | // 4:6 disposal 0 | // 7 user input - 0 = none transp )); // 8 transparency flag WriteShort(delay); // delay x 1/100 sec fs.WriteByte( Convert.ToByte( transIndex)); // transparent color index fs.WriteByte(0); // block terminator } /** * Writes Image Descriptor */ protected void WriteImageDesc() { fs.WriteByte(0x2c); // image separator WriteShort(0); // image position x,y = 0,0 WriteShort(0); WriteShort(width); // image size WriteShort(height); // packed fields if (firstFrame) { // no LCT - GCT is used for first (or only) frame fs.WriteByte(0); } else { // specify normal LCT fs.WriteByte( Convert.ToByte( 0x80 | // 1 local color table 1=yes 0 | // 2 interlace - 0=no 0 | // 3 sorted - 0=no 0 | // 4-5 reserved palSize ) ); // 6-8 size of color table } } /** * Writes Logical Screen Descriptor */ protected void WriteLSD() { // logical screen size WriteShort(width); WriteShort(height); // packed fields fs.WriteByte( Convert.ToByte (0x80 | // 1 : global color table flag = 1 (gct used) 0x70 | // 2-4 : color resolution = 7 0x00 | // 5 : gct sort flag = 0 palSize) ); // 6-8 : gct size fs.WriteByte(0); // background color index fs.WriteByte(0); // pixel aspect ratio - assume 1:1 } /** * Writes Netscape application extension to define * repeat count. */ protected void WriteNetscapeExt() { fs.WriteByte(0x21); // extension introducer fs.WriteByte(0xff); // app extension label fs.WriteByte(11); // block size WriteString("NETSCAPE" + "2.0"); // app id + auth code fs.WriteByte(3); // sub-block size fs.WriteByte(1); // loop sub-block id WriteShort(repeat); // loop count (extra iterations, 0=repeat forever) fs.WriteByte(0); // block terminator } /** * Writes color table */ protected void WritePalette() { fs.Write(colorTab, 0, colorTab.Length); int n = (3 * 256) - colorTab.Length; for (int i = 0; i < n; i++) { fs.WriteByte(0); } } /** * Encodes and writes pixel data */ protected void WritePixels() { LZWEncoder encoder = new LZWEncoder(width, height, indexedPixels, colorDepth); encoder.Encode( fs ); } /** * Write 16-bit value to output stream, LSB first */ protected void WriteShort(int value) { fs.WriteByte( Convert.ToByte( value & 0xff)); fs.WriteByte( Convert.ToByte( (value >> 8) & 0xff )); } /** * Writes string to output stream */ protected void WriteString(String s) { char[] chars = s.ToCharArray(); for (int i = 0; i < chars.Length; i++) { fs.WriteByte((byte) chars[i]); } } } }很多代码啊 就不全贴出来了 大家慢慢看吧 效果还行 只是可惜小的GIF图片有延迟
[ 本帖最后由 wangnannan 于 2010-12-20 13:16 编辑 ]