private byte[] ReadFrameLocalColorTable(GifImageDescriptor imageDescriptor) { byte[] localColorTable = null; if (imageDescriptor.LocalColorTableFlag) { localColorTable = new byte[imageDescriptor.LocalColorTableSize * 3]; currentStream.Read(localColorTable, 0, localColorTable.Length); } return(localColorTable); }
public void TestPackedValue() { Assert.Equal(128, GifImageDescriptor.GetPackedValue(true, false, false, 1)); // localColorTable Assert.Equal(64, GifImageDescriptor.GetPackedValue(false, true, false, 1)); // interfaceFlag Assert.Equal(32, GifImageDescriptor.GetPackedValue(false, false, true, 1)); // sortFlag Assert.Equal(224, GifImageDescriptor.GetPackedValue(true, true, true, 1)); // all Assert.Equal(7, GifImageDescriptor.GetPackedValue(false, false, false, 8)); Assert.Equal(227, GifImageDescriptor.GetPackedValue(true, true, true, 4)); Assert.Equal(231, GifImageDescriptor.GetPackedValue(true, true, true, 8)); }
private void Read(Stream stream, IEnumerable <GifExtension> controlExtensions, bool metadataOnly) { //Note: at this point, the Image Separator (0x2C) has already been read Descriptor = GifImageDescriptor.ReadImageDescriptor(stream); if (Descriptor.HasLocalColorTable) { LocalColorTable = GifHelpers.ReadColorTable(stream, Descriptor.LocalColorTableSize); } ImageData = GifImageData.ReadImageData(stream, metadataOnly); Extensions = controlExtensions.ToList().AsReadOnly(); }
private async Task RenderFrameAsync(int frameIndex, CancellationToken cancellationToken) { if (frameIndex < 0) { return; } GifFrame frame = this._metadata.Frames[frameIndex]; GifImageDescriptor desc = frame.Descriptor; using (Stream indexStreamAsync = await this.GetIndexStreamAsync(frame, cancellationToken)) { if (frameIndex < this._previousFrameIndex) { this.ClearArea((IGifRect)this._metadata.Header.LogicalScreenDescriptor); } else { this.DisposePreviousFrame(frame); } int length = 4 * desc.Width; byte[] buffer = new byte[desc.Width]; byte[] numArray = new byte[length]; Animator.GifPalette palette = this._palettes[frameIndex]; int num1 = palette.TransparencyIndex ?? -1; foreach (int num2 in frame.Descriptor.Interlace ? Animator.InterlacedRows(frame.Descriptor.Height) : Animator.NormalRows(frame.Descriptor.Height)) { if (indexStreamAsync.Read(buffer, 0, desc.Width) != desc.Width) { throw new EndOfStreamException(); } int offset = (desc.Top + num2) * this._stride + desc.Left * 4; if (num1 >= 0) { Animator.CopyFromBitmap(numArray, this._bitmap, offset, length); } for (int index = 0; index < desc.Width; ++index) { byte num3 = buffer[index]; int startIndex = 4 * index; if ((int)num3 != num1) { Animator.WriteColor(numArray, palette[(int)num3], startIndex); } } Animator.CopyToBitmap(numArray, this._bitmap, offset, length); } this._bitmap.Invalidate(); this._previousFrame = frame; this._previousFrameIndex = frameIndex; } }
static void CalculColors(GifData gifData) { Color[] previousFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; Color[] currentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; Color[] transparentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; // Create sprites for (int i = 0; i < gifData.graphicsControlExtensions.Count; i++) { GifGraphicsControlExtension graphicsControlExt = gifData.graphicsControlExtensions[i]; GifImageDescriptor imageDescriptor = graphicsControlExt.imageDescriptor; GifImageData imageData = imageDescriptor.imageData; int top = imageDescriptor.imageTop; int left = imageDescriptor.imageLeft; int disposalMethod = graphicsControlExt.disposalMethod; int transparencyIndex = graphicsControlExt.transparentColorFlag ? graphicsControlExt.transparentColorIndex : -1; Color[] colorTabel = imageData.imageDescriptor.localColorTableFlag ? imageData.imageDescriptor.localColorTable : gifData.globalColorTable; for (int j = 0; j < imageDescriptor.imageWidth; j++) { for (int k = 0; k < imageDescriptor.imageHeight; k++) { int x = left + j; int y = (gifData.canvasHeight - 1) - (top + k); int colorIndex = imageData.colorIndices[j + k * imageDescriptor.imageWidth]; int pixelOffset = x + y * gifData.canvasWidth; if (colorIndex != transparencyIndex) { currentFrame[pixelOffset] = colorTabel[colorIndex];//imageData.getColor(colorIndex); } } } // Set texture pixels and create sprite // Store current frame as previous before continuing, and reset current frame currentFrame.CopyTo(previousFrame, 0); if (disposalMethod == 0 || disposalMethod == 2) { currentFrame = new Color[currentFrame.Length]; imageData.colors = currentFrame; } else { imageData.colors = new Color[currentFrame.Length]; currentFrame.CopyTo(imageData.colors, 0); } } }
private void ReadFrame() { GifImageDescriptor imageDescriptor = ReadImageDescriptor(); byte[] localColorTable = ReadFrameLocalColorTable(imageDescriptor); byte[] indices = ReadFrameIndices(imageDescriptor); // Determine the color table for this frame. If there is a local one, use it // otherwise use the global color table. byte[] colorTable = localColorTable ?? globalColorTable; ReadFrameColors(indices, colorTable, imageDescriptor); // Skip any remaining blocks Skip(0); }
private GifImageDescriptor ReadImageDescriptor() { byte[] buffer = new byte[9]; currentStream.Read(buffer, 0, buffer.Length); byte packed = buffer[8]; GifImageDescriptor imageDescriptor = new GifImageDescriptor { Left = BitConverter.ToInt16(buffer, 0), Top = BitConverter.ToInt16(buffer, 2), Width = BitConverter.ToInt16(buffer, 4), Height = BitConverter.ToInt16(buffer, 6), LocalColorTableFlag = ((packed & 0x80) >> 7) == 1, LocalColorTableSize = 2 << (packed & 0x07), InterlaceFlag = ((packed & 0x40) >> 6) == 1 }; return(imageDescriptor); }
/// <summary> /// <p>Sets new stream to read gif data from</p> /// <br/> /// <p>GifStream is reusable, you can change stream and read new gif from it. /// That way you reuse allocations that you've made, and keep your memory usage to minimum</p> /// <br/> /// <p>Stream will be reset to its initial state</p> /// </summary> /// <param name="stream">new stream with gif data</param> /// <param name="disposePrevious">Dispose previous stream</param> public void SetStream(Stream stream, bool disposePrevious = false) { if (disposePrevious) { if (currentStream != null) { currentStream.Dispose(); } } header = new GifHeader(); imageDescriptor = new GifImageDescriptor(); graphicControl = new GifGraphicControl(); currentStream = stream; CurrentToken = Token.Header; blockReader.SetStream(stream); }
private GifImageDescriptor ReadImageDescriptor() { byte[] buffer = new byte[9]; _stream.Read(buffer, 0, buffer.Length); byte packed = buffer[8]; GifImageDescriptor imageDescriptor = new GifImageDescriptor(); imageDescriptor.Left = BitConverter.ToInt16(buffer, 0); imageDescriptor.Top = BitConverter.ToInt16(buffer, 2); imageDescriptor.Width = BitConverter.ToInt16(buffer, 4); imageDescriptor.Height = BitConverter.ToInt16(buffer, 6); imageDescriptor.LocalColorTableFlag = ((packed & 0x80) >> 7) == 1; imageDescriptor.LocalColorTableSize = 2 << (packed & 0x07); imageDescriptor.InterlaceFlag = ((packed & 0x40) >> 6) == 1; return(imageDescriptor); }
private void ReadFrame() { GifImageDescriptor imageDescriptor = ReadImageDescriptor(); byte[] localColorTable = ReadFrameLocalColorTable(imageDescriptor); byte[] indices = ReadFrameIndices(imageDescriptor); // Determine the color table for this frame. If there is a local one, use it // otherwise use the global color table. byte[] colorTable = localColorTable != null ? localColorTable : _globalColorTable; ReadFrameColors(indices, colorTable, imageDescriptor); int blockSize = _stream.ReadByte(); if (blockSize > 0) { _stream.Seek(blockSize, SeekOrigin.Current); } }
private GifImageDescriptor readImageDescriptor(GifData gifData, byte[] bytes, int offset) { GifImageDescriptor id = new GifImageDescriptor(gifData); id.imageLeft = BitHelper.getInt16FromBytes(bytes, offset + 1); id.imageTop = BitHelper.getInt16FromBytes(bytes, offset + 3); id.imageWidth = BitHelper.getInt16FromBytes(bytes, offset + 5); id.imageHeight = BitHelper.getInt16FromBytes(bytes, offset + 7); id.localColorTableFlag = BitHelper.getIntFromPackedByte(bytes[offset + 9], 0, 1) == 1; id.interlaceFlag = BitHelper.getIntFromPackedByte(bytes[offset + 9], 1, 2) == 1; id.sortFlag = BitHelper.getIntFromPackedByte(bytes[offset + 9], 2, 3) == 1; id.localColorTableSize = BitHelper.getIntFromPackedByte(bytes[offset + 9], 5, 8); // Interlace flag if (id.interlaceFlag) { throw new NotImplementedException("Use of interlace flag not implemented."); } return(id); }
static List <Texture2D> CreateAnimator(GifData gifData) { List <Texture2D> sprites = new List <Texture2D>(); // Create sprites for (int i = 0; i < gifData.graphicsControlExtensions.Count; i++) { GifGraphicsControlExtension graphicsControlExt = gifData.graphicsControlExtensions[i]; GifImageDescriptor imageDescriptor = graphicsControlExt.imageDescriptor; GifImageData imageData = imageDescriptor.imageData; Texture2D texture = new Texture2D(gifData.canvasWidth, gifData.canvasHeight); // Set texture pixels and create sprite texture.SetPixels(imageData.colors); texture.Apply(); texture.filterMode = FilterMode.Point; sprites.Add(texture); } return(sprites); }
public void CreateNextTexture() { if (textures == null) { textures = new List <Texture2D>(); } int c = decodeCount; for (int i = createCount; i < c; i++) { GifGraphicsControlExtension graphicsControlExt = graphicsControlExtensions[i]; GifImageDescriptor imageDescriptor = graphicsControlExt.imageDescriptor; GifImageData imageData = imageDescriptor.imageData; Texture2D texture = new Texture2D(canvasWidth, canvasHeight); texture.SetPixels(imageData.colors); texture.Apply(); texture.filterMode = FilterMode.Point; textures.Add(texture); } createCount = c; }
private static FrameMetadata GetFrameMetadata(GifFrame gifMetadata) { GifImageDescriptor descriptor = gifMetadata.Descriptor; FrameMetadata metadata = new FrameMetadata { Left = descriptor.Left, Top = descriptor.Top, Width = descriptor.Width, Height = descriptor.Height, Delay = TimeSpan.FromMilliseconds(100.0), DisposalMethod = FrameDisposalMethod.None }; GifGraphicControlExtension extension = gifMetadata.Extensions.OfType <GifGraphicControlExtension>().FirstOrDefault <GifGraphicControlExtension>(); if (extension != null) { if (extension.Delay != 0) { metadata.Delay = TimeSpan.FromMilliseconds((double)extension.Delay); } metadata.DisposalMethod = (FrameDisposalMethod)extension.DisposalMethod; } return(metadata); }
private byte[] ReadFrameLocalColorTable(GifImageDescriptor imageDescriptor) { byte[] localColorTable = null; if (imageDescriptor.LocalColorTableFlag == true) { localColorTable = new byte[imageDescriptor.LocalColorTableSize * 3]; _stream.Read(localColorTable, 0, localColorTable.Length); } return localColorTable; }
private void createAnimator(GifData gifData) { List <Sprite> sprites = new List <Sprite>(); GifAnimatorScript animatorScript = gameObject.AddComponent <GifAnimatorScript>(); Color[] previousFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; Color[] currentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; Color[] transparentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; // Create sprites for (int i = 0; i < gifData.graphicsControlExtensions.Count; i++) { GifGraphicsControlExtension graphicsControlExt = gifData.graphicsControlExtensions[i]; GifImageDescriptor imageDescriptor = graphicsControlExt.imageDescriptor; GifImageData imageData = imageDescriptor.imageData; int top = imageDescriptor.imageTop; int left = imageDescriptor.imageLeft; int disposalMethod = graphicsControlExt.disposalMethod; Texture2D texture = new Texture2D(gifData.canvasWidth, gifData.canvasHeight); int transparencyIndex = graphicsControlExt.transparentColorFlag ? graphicsControlExt.transparentColorIndex : -1; // Determine base pixels if (i == 0) { texture.SetPixels(transparentFrame); } else { if (disposalMethod == 1) { texture.SetPixels(previousFrame); } else if (disposalMethod == 2) { texture.SetPixels(transparentFrame); } else if (disposalMethod == 3) { throw new NotImplementedException("Disposal method 3 is not implemented."); } } // Set pixels from image data for (int j = 0; j < imageDescriptor.imageWidth; j++) { for (int k = 0; k < imageDescriptor.imageHeight; k++) { int x = left + j; int y = (gifData.canvasHeight - 1) - (top + k); int colorIndex = imageData.colorIndices[j + k * imageDescriptor.imageWidth]; int pixelOffset = x + y * gifData.canvasWidth; if (colorIndex != transparencyIndex) { GifColor gifColor = imageData.getColor(colorIndex); currentFrame[pixelOffset] = new Color(gifColor.r / 255f, gifColor.g / 255f, gifColor.b / 255f); } } } //float bgMax = 50f / 255; //var transparent = currentFrame.Where(p => p.a == 0); //var bgMeanSum = currentFrame.Aggregate(new float[8], (curSum, color) => //{ // curSum[4] += color.a; // ++curSum[5]; // if (color.a > 0) // { // curSum[6] += color.a; // ++curSum[7]; // } // if (color.r >= bgMax || color.g >= bgMax || color.b >= bgMax) // return curSum; // We are interested on dark colors // curSum[0] += color.r; // curSum[1] += color.g; // curSum[2] += color.b; // ++curSum[3]; // return curSum; //}); //var bgMean = new Color32( // (byte)(bgMeanSum[0] * 255 / bgMeanSum[3]), // (byte)(bgMeanSum[1] * 255 / bgMeanSum[3]), // (byte)(bgMeanSum[2] * 255 / bgMeanSum[3]), // (byte)(bgMeanSum[4] * 255 / bgMeanSum[5])); //Debug.Log( // $"Frame {i} has transparent colors?: {transparent.Any()} || Count: {transparent.Count()} || Background: {bgMean}" + // Environment.NewLine + // $"Solid transparency mean (must be 255): {(byte)(bgMeanSum[6] * 255 / bgMeanSum[7])}"); // Set texture pixels and create sprite texture.SetPixels(currentFrame); texture.Apply(); texture.filterMode = FilterMode.Point; sprites.Add(Sprite.Create(texture, new Rect(0f, 0f, gifData.canvasWidth, gifData.canvasHeight), new Vector2(1f, 1f))); // Store current frame as previous before continuing, and reset current frame currentFrame.CopyTo(previousFrame, 0); if (disposalMethod == 0 || disposalMethod == 2) { currentFrame = new Color[currentFrame.Length]; } } // Setup animator script animatorScript.sprites = sprites; }
private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor) { int imageWidth = _logicalScreenDescriptor.Width; int imageHeight = _logicalScreenDescriptor.Height; if (_currentFrame == null) { _currentFrame = new byte[imageWidth * imageHeight * 4]; } byte[] lastFrame = null; if (_graphicsControl != null && _graphicsControl.DisposalMethod == DisposalMethod.RestoreToPrevious) { lastFrame = new byte[imageWidth * imageHeight * 4]; Array.Copy(_currentFrame, lastFrame, lastFrame.Length); } int offset = 0, i = 0, index = -1; int iPass = 0; // the interlace pass int iInc = 8; // the interlacing line increment int iY = 0; // the current interlaced line int writeY = 0; // the target y offset to write to for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) { // Check if this image is interlaced. if (descriptor.InterlaceFlag) { // If so then we read lines at predetermined offsets. // When an entire image height worth of offset lines has been read we consider this a pass. // With each pass the number of offset lines changes and the starting line changes. if (iY >= descriptor.Height) { iPass++; switch (iPass) { case 1: iY = 4; break; case 2: iY = 2; iInc = 4; break; case 3: iY = 1; iInc = 2; break; } } writeY = iY + descriptor.Top; iY += iInc; } else { writeY = y; } for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) { offset = writeY * imageWidth + x; index = indices[i]; if (_graphicsControl == null || _graphicsControl.TransparencyFlag == false || _graphicsControl.TransparencyIndex != index) { _currentFrame[offset * 4 + 0] = colorTable[index * 3 + 0]; _currentFrame[offset * 4 + 1] = colorTable[index * 3 + 1]; _currentFrame[offset * 4 + 2] = colorTable[index * 3 + 2]; _currentFrame[offset * 4 + 3] = (byte)255; } i++; } } byte[] pixels = new byte[imageWidth * imageHeight * 4]; Array.Copy(_currentFrame, pixels, pixels.Length); _currentFrame = new byte[imageWidth * imageHeight * 4]; Image frame = new Image(imageWidth, imageHeight); int indx = 0; byte r, g, b, a; for (uint y = 0; y < frame.Height; y++) { for (uint x = 0; x < frame.Width; x++) { r = pixels[indx]; indx++; g = pixels[indx]; indx++; b = pixels[indx]; indx++; a = pixels[indx]; indx++; frame.SetPixel(x, y, new Pixel(r, g, b, a)); } } pixels = null; System.GC.Collect(); _image.AddFrame(frame); if (_graphicsControl != null) { if (_graphicsControl.DelayTime > 0) { _image.TimePerFrame = _graphicsControl.DelayTime; } if (_graphicsControl.DisposalMethod == DisposalMethod.RestoreToBackground) { Image im = new Image(imageWidth, imageHeight); im.Clear(new Pixel(true)); _image.AddFrame(im); _image.Loop = false; } else if (_graphicsControl.DisposalMethod == DisposalMethod.RestoreToPrevious) { _image.Loop = true; } } }
private void AddFramDimensions(GifImageDescriptor.ImageDescriptor id) { FrameDimensions frame = new FrameDimensions(); frame.Set( id.Left, id.Top,id.Width, id.Height); DimensionList.Add(frame); }
public void Set(GifGraphicsControlExtension.GraphicsControlExtension g, GifImageDescriptor.ImageDescriptor id, GifImageData.ImageData d) { GCE = g; desciptor = id; data = d; }
private byte[] ReadFrameIndices(GifImageDescriptor imageDescriptor) { int dataSize = _stream.ReadByte(); LZWDecoder lzwDecoder = new LZWDecoder(_stream); byte[] indices = lzwDecoder.DecodePixels(imageDescriptor.Width, imageDescriptor.Height, dataSize); return indices; }
private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor) { int imageWidth = _descriptor.Width; int imageHeight = _descriptor.Height; if (_currentFrame == null) { _currentFrame = new byte[imageWidth * imageHeight * 4]; } byte[] lastFrame = null; if (_graphicsControl != null && _graphicsControl.DisposalMethod == DisposalMethod.RestoreToPrevious) { lastFrame = new byte[imageWidth * imageHeight * 4]; Array.Copy(_currentFrame, lastFrame, lastFrame.Length); } int offset = 0, i = 0, index = -1; int iPass = 0; // the interlace pass int iInc = 8; // the interlacing line increment int iY = 0; // the current interlaced line int writeY = 0; // the target y offset to write to for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) { // Check if this image is interlaced. if (descriptor.InterlaceFlag) { // If so then we read lines at predetermined offsets. // When an entire image height worth of offset lines has been read we consider this a pass. // With each pass the number of offset lines changes and the starting line changes. if (iY >= descriptor.Height) { iPass++; switch (iPass) { case 1: iY = 4; break; case 2: iY = 2; iInc = 4; break; case 3: iY = 1; iInc = 2; break; } } writeY = iY + descriptor.Top; iY += iInc; } else { writeY = y; } for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) { offset = writeY * imageWidth + x; index = indices[i]; if (_graphicsControl == null || _graphicsControl.TransparencyFlag == false || _graphicsControl.TransparencyIndex != index) { _currentFrame[offset * 4 + 0] = colorTable[index * 3 + 2]; _currentFrame[offset * 4 + 1] = colorTable[index * 3 + 1]; _currentFrame[offset * 4 + 2] = colorTable[index * 3 + 0]; _currentFrame[offset * 4 + 3] = (byte)255; } i++; } } var pixels = new byte[imageWidth * imageHeight * 4]; Array.Copy(_currentFrame, pixels, pixels.Length); _frames.Add(new Image(imageWidth, imageHeight, pixels)); if (_graphicsControl != null) { if (_graphicsControl.DisposalMethod == DisposalMethod.RestoreToBackground) { for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) { for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) { offset = y * imageWidth + x; _currentFrame[offset * 4 + 0] = 0; _currentFrame[offset * 4 + 1] = 0; _currentFrame[offset * 4 + 2] = 0; _currentFrame[offset * 4 + 3] = 0; } } } else if (_graphicsControl.DisposalMethod == DisposalMethod.RestoreToPrevious) { _currentFrame = lastFrame; } } }
private void ReadFrameColors(byte[] indices, byte[] colorTable, GifImageDescriptor descriptor) { int imageWidth = logicalScreenDescriptor.Width; int imageHeight = logicalScreenDescriptor.Height; if (currentFrame == null) { currentFrame = new Color2[imageWidth * imageHeight]; } Color2[] lastFrame = null; if (graphicsControlExtension != null && graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious) { lastFrame = new Color2[imageWidth * imageHeight]; Array.Copy(currentFrame, lastFrame, lastFrame.Length); } int offset, i = 0; int interlacePass = 0; // The interlace pass int interlaceIncrement = 8; // The interlacing line increment int interlaceY = 0; // The current interlaced line for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) { // Check if this image is interlaced. int writeY; // the target y offset to write to if (descriptor.InterlaceFlag) { // If so then we read lines at predetermined offsets. // When an entire image height worth of offset lines has been read we consider this a pass. // With each pass the number of offset lines changes and the starting line changes. if (interlaceY >= descriptor.Height) { interlacePass++; switch (interlacePass) { case 1: interlaceY = 4; break; case 2: interlaceY = 2; interlaceIncrement = 4; break; case 3: interlaceY = 1; interlaceIncrement = 2; break; } } writeY = interlaceY + descriptor.Top; interlaceY += interlaceIncrement; } else { writeY = y; } for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) { offset = (writeY * imageWidth) + x; int index = indices[i]; if (graphicsControlExtension == null || graphicsControlExtension.TransparencyFlag == false || graphicsControlExtension.TransparencyIndex != index) { // Stored in r-> g-> b-> a order. int indexOffset = index * 3; Color2 pixel = Color2.FromArgb(colorTable[indexOffset], colorTable[indexOffset + 1], colorTable[indexOffset + 2]); currentFrame[offset] = pixel; } i++; } } Color2[] pixels = new Color2[imageWidth * imageHeight]; Array.Copy(currentFrame, pixels, pixels.Length); ImageBase currentImage; if (decodedImage.Pixels == null) { currentImage = decodedImage; currentImage.SetPixels(imageWidth, imageHeight, pixels); currentImage.Quality = colorTable.Length / 3; if (graphicsControlExtension != null && graphicsControlExtension.DelayTime > 0) { decodedImage.FrameDelay = graphicsControlExtension.DelayTime; } } else { ImageFrame frame = new ImageFrame(); currentImage = frame; currentImage.SetPixels(imageWidth, imageHeight, pixels); currentImage.Quality = colorTable.Length / 3; if (graphicsControlExtension != null && graphicsControlExtension.DelayTime > 0) { currentImage.FrameDelay = graphicsControlExtension.DelayTime; } decodedImage.Frames.Add(frame); } if (graphicsControlExtension != null) { if (graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground) { for (int y = descriptor.Top; y < descriptor.Top + descriptor.Height; y++) { for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width; x++) { offset = (y * imageWidth) + x; // Stored in r-> g-> b-> a order. currentFrame[offset] = default(Color2); } } } else if (graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious) { currentFrame = lastFrame; } } }
private void createAnimator(GifData gifData) { List <Sprite> sprites = new List <Sprite>(); GifAnimatorScript animatorScript = gameObject.AddComponent <GifAnimatorScript>(); Color[] previousFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; Color[] currentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; Color[] transparentFrame = new Color[gifData.canvasWidth * gifData.canvasHeight]; // Create sprites for (int i = 0; i < gifData.graphicsControlExtensions.Count; i++) { GifGraphicsControlExtension graphicsControlExt = gifData.graphicsControlExtensions[i]; GifImageDescriptor imageDescriptor = graphicsControlExt.imageDescriptor; GifImageData imageData = imageDescriptor.imageData; int top = imageDescriptor.imageTop; int left = imageDescriptor.imageLeft; int disposalMethod = graphicsControlExt.disposalMethod; Texture2D texture = new Texture2D(gifData.canvasWidth, gifData.canvasHeight); int transparencyIndex = graphicsControlExt.transparentColorFlag ? graphicsControlExt.transparentColorIndex : -1; // Determine base pixels if (i == 0) { texture.SetPixels(transparentFrame); } else { if (disposalMethod == 1) { texture.SetPixels(previousFrame); } else if (disposalMethod == 2) { texture.SetPixels(transparentFrame); } else if (disposalMethod == 3) { throw new NotImplementedException("Disposal method 3 is not implemented."); } } // Set pixels from image data for (int j = 0; j < imageDescriptor.imageWidth; j++) { for (int k = 0; k < imageDescriptor.imageHeight; k++) { int x = left + j; int y = (gifData.canvasHeight - 1) - (top + k); int colorIndex = imageData.colorIndices[j + k * imageDescriptor.imageWidth]; int pixelOffset = x + y * gifData.canvasWidth; if (colorIndex != transparencyIndex) { GifColor gifColor = imageData.getColor(colorIndex); currentFrame[pixelOffset] = new Color(gifColor.r / 255f, gifColor.g / 255f, gifColor.b / 255f); } } } // Set texture pixels and create sprite texture.SetPixels(currentFrame); texture.Apply(); texture.filterMode = FilterMode.Point; sprites.Add(Sprite.Create(texture, new Rect(0f, 0f, gifData.canvasWidth, gifData.canvasHeight), new Vector2(1f, 1f))); // Store current frame as previous before continuing, and reset current frame currentFrame.CopyTo(previousFrame, 0); if (disposalMethod == 0 || disposalMethod == 2) { currentFrame = new Color[currentFrame.Length]; } } // Setup animator script animatorScript.sprites = sprites; }
private GifImageDescriptor ReadImageDescriptor() { byte[] buffer = new byte[9]; _stream.Read(buffer, 0, buffer.Length); byte packed = buffer[8]; GifImageDescriptor imageDescriptor = new GifImageDescriptor(); imageDescriptor.Left = BitConverter.ToInt16(buffer, 0); imageDescriptor.Top = BitConverter.ToInt16(buffer, 2); imageDescriptor.Width = BitConverter.ToInt16(buffer, 4); imageDescriptor.Height = BitConverter.ToInt16(buffer, 6); imageDescriptor.LocalColorTableFlag = ((packed & 0x80) >> 7) == 1; imageDescriptor.LocalColorTableSize = 2 << (packed & 0x07); imageDescriptor.InterlaceFlag = ((packed & 0x40) >> 6) == 1; return imageDescriptor; }