⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 animatedgifencoder.cs

📁 该即时通讯系统系统能够实现像QQ一样的通讯功能
💻 CS
字号:
using System;
using System.Drawing;
using System.IO;

namespace LanMsg.Gif.Components
{
	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 = ( 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 );
			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]);
			}
		}
	}

}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -