public void Load(Reader reader) { // Read the header: reader.ReadString(6); Width = reader.ReadInt16(); Height = reader.ReadInt16(); if (HostSPA == null) { // Create the host SPA (default 100fps): HostSPA = new SPA(Width, Height, 100); } // Apply parent: HostSPA.ParentGif = this; byte packed = (byte)reader.ReadByte(); bool colorTableFlag = ((packed & 0x80) >> 7) == 1; ColorResolution = (byte)((packed & 0x60) >> 5); SortFlags = ((byte)(packed & 0x10)) >> 4; // Background index (unused): byte bgIndex = (byte)reader.ReadByte(); PixelAspect = (byte)reader.ReadByte(); Color32[] globalColorTable = null; BackgroundColour = new Color32(0, 0, 0, 0); if (colorTableFlag) { int colorTableSize = ((int)2) << (packed & 7); globalColorTable = LoadPalette(reader.ReadBytes(colorTableSize * 3)); if (bgIndex < globalColorTable.Length) { BackgroundColour = globalColorTable[bgIndex]; } } byte nextFlag = (byte)reader.ReadByte(); int frameCount = 0; int gcbCount = 0; Color32[] previousFrame = null; List <SPASprite> spaFrames = new List <SPASprite>(); List <GifFrame> frames = new List <GifFrame>(); while (nextFlag != GifBlocks.Terminator) { if (nextFlag == GifBlocks.ImageLabel) { GifFrame frame; if (frames.Count <= frameCount) { // Create the frame now: frame = new GifFrame(this, frameCount); frames.Add(frame); } else { // Load it: frame = frames[frameCount]; } // Drop zero-delay frames from the output. // - This makes "full colour" GIFs work. if (frame.Delay != 0f || spaFrames.Count == 0) { spaFrames.Add(frame); } previousFrame = ReadFrame(previousFrame, frame, reader, globalColorTable); frameCount++; } else if (nextFlag == GifBlocks.ExtensionIntroducer) { int gcl = reader.ReadByte(); switch (gcl) { case GifBlocks.GraphicControlLabel: int blockSize = reader.ReadByte(); if (blockSize != 4) { throw new Exception("A graphic extension block had the wrong size in a GIF stream."); } byte gPacked = (byte)reader.ReadByte(); bool transparencyFlag = (gPacked & 0x01) == 1; int disposalMethod = (gPacked & 0x1C) >> 2; // Frame delay in seconds: float delay = (float)reader.ReadInt16() / 100f; byte transparencyIndex = (byte)reader.ReadByte(); // Terminal 0: reader.ReadByte(); GifFrame frame; if (frames.Count <= gcbCount) { // Create the frame now: frame = new GifFrame(this, gcbCount); frames.Add(frame); } else { // Load it: frame = frames[gcbCount]; } // Apply delay: frame.Delay = delay; frame.DisposalMethod = disposalMethod; if (transparencyFlag) { frame.TransparencyIndex = transparencyIndex; } else { frame.TransparencyIndex = -1; } gcbCount++; break; case GifBlocks.CommentLabel: CommentBlock commentBlock = new CommentBlock(); commentBlock.Load(reader); Blocks.Add(commentBlock); break; case GifBlocks.ApplicationExtensionLabel: ApplicationExtensionBlock appBlock = new ApplicationExtensionBlock(); appBlock.Load(reader); Blocks.Add(appBlock); break; case GifBlocks.PlainTextLabel: PlainTextBlock texBlock = new PlainTextBlock(); texBlock.Load(reader); Blocks.Add(texBlock); break; } } else if (nextFlag == GifBlocks.EndIntroducer) { break; } nextFlag = reader.ReadByte(); } Frames = frames.ToArray(); // Apply the frames to the host SPA: HostSPA.Sprites = spaFrames.ToArray(); }
public static Color32[] LoadFramePixels(Color32[] prevImage, byte[] pixels, Color32[] colorTable, bool interlaceFlag, GifFrame frame) { Gif gif = frame.Gif; int fw = frame.Width; int iw = gif.Width; int ih = gif.Height; // Get transparency index: int transIndex = frame.TransparencyIndex; // Based on disposal method, we may actually be using prevImage. Color32[] fullImage = prevImage; int disposal = frame.DisposalMethod; int maxY = ih - 1; bool drawTransparent = (disposal == 2); /* * if(disposal==0){ * // Undefined - do nothing. * // - Safe to reuse prevImage here. * }else if(disposal==1){ * // Don't dispose. Return the frame from this function. * // - Safe to reuse prevImage here. * }else if(disposal==2){ * // Restore to background. * // - Safe to reuse prevImage here. * } */ if (disposal == 3) { // Restore to previous. Return prevImage. // - Can't reuse prevImage here. fullImage = null; } // Create the image area if one is needed: if (fullImage == null) { fullImage = new Color32[iw * ih]; } // Got a previous image? if (prevImage != null && prevImage != fullImage) { // Blit previous into fullImage: Array.Copy(prevImage, 0, fullImage, 0, fullImage.Length); } int startRowPoint = ((maxY - frame.OffsetY) * iw); int offSet = 0; if (interlaceFlag) { int i = 0; int row = 0; int rowPoint = startRowPoint; int pass = 0; while (pass < 4) { if (pass == 1) { rowPoint = startRowPoint - (4 * iw); offSet += 4 * fw; } else if (pass == 2) { rowPoint = startRowPoint - (2 * iw); offSet += 2 * fw; } else if (pass == 3) { rowPoint = startRowPoint - (1 * iw); offSet += 1 * fw; } int rate = 1; if (pass == 0 | pass == 1) { rate = 7; } else if (pass == 2) { rate = 3; } while (i < pixels.Length) { int colIndex = pixels[i++]; if (colIndex == transIndex) { if (drawTransparent) { fullImage[rowPoint + row + frame.OffsetX] = new Color32(0, 0, 0, 0); } } else { fullImage[rowPoint + row + frame.OffsetX] = colorTable[colIndex]; } row++; offSet++; if (row == fw) { // End of the row row = 0; rowPoint -= (rate + 1) * iw; offSet += (fw * rate); if (offSet >= pixels.Length) { pass++; offSet = 0; break; } } } } } else { int row = 0; int rowPoint = startRowPoint; for (int i = 0; i < pixels.Length; i++) { int colIndex = pixels[i]; if (colIndex == transIndex) { if (drawTransparent) { fullImage[rowPoint + row + frame.OffsetX] = new Color32(0, 0, 0, 0); } } else { fullImage[rowPoint + row + frame.OffsetX] = colorTable[colIndex]; } row++; if (row == fw) { row = 0; rowPoint -= iw; } } } // Create frame texture: Texture2D tex = new Texture2D(frame.Gif.Width, frame.Gif.Height); tex.SetPixels32(fullImage); // Make sure it filters correctly. // This is so we don't see parts of other frames around the edge of the image onscreen: tex.filterMode = FilterMode.Point; tex.Apply(); frame.Sprite = tex; if (disposal == 3) { return(prevImage); } if (disposal == 2) { // Restore to background. int graphicSize = fw * frame.Height; int row = 0; int rowPoint = startRowPoint; Color32 background = gif.BackgroundColour; for (int i = 0; i < graphicSize; i++) { fullImage[rowPoint + row + frame.OffsetX] = background; row++; if (row == fw) { // End of the row row = 0; rowPoint -= iw; } } } return(fullImage); }