public static Type Extract(BinaryReader Reader, out Extension Extension) { Type type = (Type)Reader.ReadByte(); switch (type) { case Type.PlainText: Extension = new ExtensionGeneric(Reader); break; //todo case Type.GraphicsControl: Extension = new ExtensionGraphicsControl(Reader); break; case Type.Comment: Extension = new ExtensionGeneric(Reader); break; //todo case Type.Application: Extension = ExtensionApplication.Extract(Reader); break; default: Extension = new ExtensionGeneric(Reader); break; } return(type); }
/// <summary> /// Reads this Gif from a Stream /// </summary> /// <param name="Stream"></param> public void Read(Stream Stream) { BinaryReader reader = new BinaryReader( Stream, Encoding.ASCII, true); ////////////////////////////////////////////// // HEADER ////////////////////////////////////////////// byte[] buffer = new byte[3]; // signature reader.Read(buffer, 0, 3); if (!buffer.SequenceEqual(Constants.SIGNATURE)) { throw new Exception("Not a GIF file"); } // version reader.Read(buffer, 0, 3); // check version if (!buffer.SequenceEqual(Constants.VERSION_89A) && !buffer.SequenceEqual(Constants.VERSION_87A)) { throw new Exception("Unsupported Version"); } ////////////////////////////////////////////// // LOGICAL SCREEN DESCRIPTOR DATA ////////////////////////////////////////////// // width & height CanvasWidth = reader.ReadUInt16(); CanvasHeight = reader.ReadUInt16(); // other data Packed.Value = reader.ReadByte(); BackgroundColorIndex = reader.ReadByte(); PixelAspectRatio = reader.ReadByte(); ////////////////////////////////////////////// // GLOBAL COLOR TABLE (OPTIONAL) ////////////////////////////////////////////// GlobalColorTable = (Packed.IsGlobalColorTable) ? reader.ReadBytes((int)Packed.ByteSizeOfColorTable) : new byte[0]; ////////////////////////////////////////////// // DYNAMIC CHUNKS (OPTIONAL, EXCEPT ONE FRAME) ////////////////////////////////////////////// ExtensionGraphicsControl lastGraphicsControl = null; while (true) { byte introducer = reader.ReadByte(); // EXTENSION if (introducer == (byte)Introducer.Extension) { // try parse it Extension extension; Extension.Type type = Extension.Extract(reader, out extension); // GraphicsControl if (type == Extension.Type.GraphicsControl) { // save it for next frame if (lastGraphicsControl == null) { lastGraphicsControl = (ExtensionGraphicsControl)extension; } // not good, we got another graphicscontrol extension // without having read a frame since then... else { // discard previous one, save this one lastGraphicsControl = (ExtensionGraphicsControl)extension; } } // Application else if (type == Extension.Type.Application) { ApplicationExtension = (ExtensionApplication)extension; } // Generic else { Extensions.Add(extension); } } // IMAGEDESCRIPTOR else if (introducer == (byte)Introducer.ImageDescriptor) { // parse frame data Frame frame = new Frame(reader); // attach the last GraphicsControl extension that was // not used yet and last read before this frame if (lastGraphicsControl != null) { frame.GraphicsControl = lastGraphicsControl; lastGraphicsControl = null; } // store frame Frames.Add(frame); } // TRAILER (PARSING SUCCESSFUL) else if (introducer == (byte)Introducer.Trailer) { break; } // UNKNOWN else { throw new Exception("Unknown Dynamic Chunk Introducer"); } } reader.Dispose(); }
public Frame(byte[] Pixels, int Width, int Height, uint[] Palette, uint ColorCount, LZWEncoder Encoder, ushort Delay, int TransparentColorIndex = -1) { if (Pixels == null) { throw new ArgumentException("Pixels can't be null."); } if (Width <= 0 || Height <= 0) { throw new ArgumentException("Width and Height must be greater 0."); } if (Palette == null || Palette.Length > 256) { throw new ArgumentException("Palette null or more than 256 entries."); } if (ColorCount > Palette.Length) { throw new ArgumentException("ColorCount bigger than Palette size."); } if (Encoder == null) { throw new ArgumentException("Encoder can't be null."); } // save provided dimension this.Width = (ushort)Width; this.Height = (ushort)Height; // encode pixels using argument encoder instance Encoder.Encode(Pixels, Chunks, Width, Height); MinLZWCodeSize = 8; // determine size of colortable to use // get next bigger power of 2 value of used colorcount uint palSize2 = NextPowerOf2(ColorCount); // use and create local color table with determined size Packed.IsLocalColorTable = true; Packed.SizeOfLocalColorTable = (uint)Math.Max((int)Math.Log(palSize2, 2.0) - 1, 0); ColorTable = new byte[palSize2 * 3]; // fill color table int i = 0; for (uint j = 0; j < ColorCount; j++) { uint c = Palette[j]; ColorTable[i] = (byte)((c & 0x00FF0000) >> 16); i++; ColorTable[i] = (byte)((c & 0x0000FF00) >> 8); i++; ColorTable[i] = (byte)(c & 0x000000FF); i++; } // set graphics control extension GraphicsControl = new ExtensionGraphicsControl(); GraphicsControl.DelayTime = Delay; GraphicsControl.Packed.IsUserInput = false; GraphicsControl.Packed.DisposalMethod = ExtensionGraphicsControl.Flags.DisposalMethods.RestoreToBackground; // possibly set transparent color index and enable transparency if (TransparentColorIndex > -1 && TransparentColorIndex < 256) { GraphicsControl.Packed.IsTransparentColor = true; GraphicsControl.TransparentColorIndex = (byte)TransparentColorIndex; } }