private void EncodeGlobal <TPixel>(Image <TPixel> image, IndexedImageFrame <TPixel> quantized, int transparencyIndex, Stream stream) where TPixel : unmanaged, IPixel <TPixel> { // The palette quantizer can reuse the same pixel map across multiple frames // since the palette is unchanging. This allows a reduction of memory usage across // multi frame gifs using a global palette. EuclideanPixelMap <TPixel> pixelMap = default; bool pixelMapSet = false; for (int i = 0; i < image.Frames.Count; i++) { ImageFrame <TPixel> frame = image.Frames[i]; ImageFrameMetadata metadata = frame.Metadata; GifFrameMetadata frameMetadata = metadata.GetGifMetadata(); this.WriteGraphicalControlExtension(frameMetadata, transparencyIndex, stream); this.WriteImageDescriptor(frame, false, stream); if (i == 0) { this.WriteImageData(quantized, stream); } else { if (!pixelMapSet) { pixelMapSet = true; pixelMap = new EuclideanPixelMap <TPixel>(this.configuration, quantized.Palette); } using var paletteFrameQuantizer = new PaletteQuantizer <TPixel>(this.configuration, this.quantizer.Options, pixelMap); using IndexedImageFrame <TPixel> paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds()); this.WriteImageData(paletteQuantized, stream); } } }
private void EncodeGlobal <TPixel>(Image <TPixel> image, IQuantizedFrame <TPixel> quantized, int transparencyIndex, Stream stream) where TPixel : struct, IPixel <TPixel> { for (int i = 0; i < image.Frames.Count; i++) { ImageFrame <TPixel> frame = image.Frames[i]; ImageFrameMetadata metadata = frame.Metadata; GifFrameMetadata frameMetadata = metadata.GetGifMetadata(); this.WriteGraphicalControlExtension(frameMetadata, transparencyIndex, stream); this.WriteImageDescriptor(frame, false, stream); if (i == 0) { this.WriteImageData(quantized, stream); } else { using (IFrameQuantizer <TPixel> paletteFrameQuantizer = new PaletteFrameQuantizer <TPixel>(this.configuration, this.quantizer.Diffuser, quantized.Palette)) { using (IQuantizedFrame <TPixel> paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } } } } }
private void EncodeLocal <TPixel>(Image <TPixel> image, QuantizedFrame <TPixel> quantized, Stream stream) where TPixel : unmanaged, IPixel <TPixel> { ImageFrame <TPixel> previousFrame = null; GifFrameMetadata previousMeta = null; foreach (ImageFrame <TPixel> frame in image.Frames) { ImageFrameMetadata metadata = frame.Metadata; GifFrameMetadata frameMetadata = metadata.GetGifMetadata(); if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. if (previousFrame != null && previousMeta.ColorTableLength != frameMetadata.ColorTableLength && frameMetadata.ColorTableLength > 0) { var options = new QuantizerOptions { Dither = this.quantizer.Options.Dither, DitherScale = this.quantizer.Options.DitherScale, MaxColors = frameMetadata.ColorTableLength }; using (IFrameQuantizer <TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer <TPixel>(this.configuration, options)) { quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); } } else { using (IFrameQuantizer <TPixel> frameQuantizer = this.quantizer.CreateFrameQuantizer <TPixel>(this.configuration)) { quantized = frameQuantizer.QuantizeFrame(frame, frame.Bounds()); } } } this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); this.WriteGraphicalControlExtension(frameMetadata, this.GetTransparentIndex(quantized), stream); this.WriteImageDescriptor(frame, true, stream); this.WriteColorTable(quantized, stream); this.WriteImageData(quantized, stream); quantized?.Dispose(); quantized = null; // So next frame can regenerate it previousFrame = frame; previousMeta = frameMetadata; } }
public void ConstructorImageFrameMetadata() { const int frameDelay = 42; const int colorTableLength = 128; const GifDisposalMethod disposalMethod = GifDisposalMethod.RestoreToBackground; var metaData = new ImageFrameMetadata(); GifFrameMetadata gifFrameMetadata = metaData.GetGifMetadata(); gifFrameMetadata.FrameDelay = frameDelay; gifFrameMetadata.ColorTableLength = colorTableLength; gifFrameMetadata.DisposalMethod = disposalMethod; var clone = new ImageFrameMetadata(metaData); GifFrameMetadata cloneGifFrameMetadata = clone.GetGifMetadata(); Assert.Equal(frameDelay, cloneGifFrameMetadata.FrameDelay); Assert.Equal(colorTableLength, cloneGifFrameMetadata.ColorTableLength); Assert.Equal(disposalMethod, cloneGifFrameMetadata.DisposalMethod); }
public void CloneIsDeep() { // arrange var exifProfile = new ExifProfile(); exifProfile.SetValue(ExifTag.Software, "UnitTest"); exifProfile.SetValue(ExifTag.Artist, "UnitTest"); var xmpProfile = new XmpProfile(new byte[0]); var iccProfile = new IccProfile() { Header = new IccProfileHeader() { CmmType = "Unittest" } }; var iptcProfile = new ImageSharp.Metadata.Profiles.Iptc.IptcProfile(); var metaData = new ImageFrameMetadata() { XmpProfile = xmpProfile, ExifProfile = exifProfile, IccProfile = iccProfile, IptcProfile = iptcProfile }; // act ImageFrameMetadata clone = metaData.DeepClone(); // assert Assert.NotNull(clone); Assert.NotNull(clone.ExifProfile); Assert.NotNull(clone.XmpProfile); Assert.NotNull(clone.IccProfile); Assert.NotNull(clone.IptcProfile); Assert.False(metaData.ExifProfile.Equals(clone.ExifProfile)); Assert.True(metaData.ExifProfile.Values.Count == clone.ExifProfile.Values.Count); Assert.False(ReferenceEquals(metaData.XmpProfile, clone.XmpProfile)); Assert.True(metaData.XmpProfile.Data.Equals(clone.XmpProfile.Data)); Assert.False(metaData.GetGifMetadata().Equals(clone.GetGifMetadata())); Assert.False(metaData.IccProfile.Equals(clone.IccProfile)); Assert.False(metaData.IptcProfile.Equals(clone.IptcProfile)); }