/// <summary> /// Decodes the image data from a specified IFD. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="tags">The IFD tags.</param> /// <param name="cancellationToken">The token to monitor cancellation.</param> /// <returns> The tiff frame. </returns> private ImageFrame <TPixel> DecodeFrame <TPixel>(ExifProfile tags, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel <TPixel> { ImageFrameMetadata imageFrameMetaData = this.ignoreMetadata ? new ImageFrameMetadata() : new ImageFrameMetadata { ExifProfile = tags, XmpProfile = tags.GetValue(ExifTag.XMP)?.Value }; TiffFrameMetadata tiffFrameMetaData = imageFrameMetaData.GetTiffMetadata(); TiffFrameMetadata.Parse(tiffFrameMetaData, tags); this.VerifyAndParse(tags, tiffFrameMetaData); int width = GetImageWidth(tags); int height = GetImageHeight(tags); var frame = new ImageFrame <TPixel>(this.Configuration, width, height, imageFrameMetaData); int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity; Number[] stripOffsets = tags.GetValue(ExifTag.StripOffsets)?.Value; Number[] stripByteCounts = tags.GetValue(ExifTag.StripByteCounts)?.Value; if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar) { this.DecodeStripsPlanar(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); } else { this.DecodeStripsChunky(frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); } return(frame); }
public void CloneIsDeep() { var metaData = new ImageFrameMetadata(); ImageFrameMetadata clone = metaData.DeepClone(); Assert.False(metaData.GetGifMetadata().Equals(clone.GetGifMetadata())); }
public void MetadataProfiles <TPixel>(TestImageProvider <TPixel> provider, bool ignoreMetadata) where TPixel : unmanaged, IPixel <TPixel> { using (Image <TPixel> image = provider.GetImage(new TiffDecoder() { IgnoreMetadata = ignoreMetadata })) { TiffMetadata meta = image.Metadata.GetTiffMetadata(); ImageFrameMetadata rootFrameMetaData = image.Frames.RootFrame.Metadata; Assert.NotNull(meta); if (ignoreMetadata) { Assert.Null(rootFrameMetaData.XmpProfile); Assert.Null(rootFrameMetaData.ExifProfile); } else { Assert.NotNull(rootFrameMetaData.XmpProfile); Assert.NotNull(rootFrameMetaData.ExifProfile); Assert.Equal(2599, rootFrameMetaData.XmpProfile.Length); Assert.Equal(26, rootFrameMetaData.ExifProfile.Values.Count); } } }
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.quantizer.Diffuser, quantized.Palette)) { using (IQuantizedFrame <TPixel> paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } } } } }
private void EncodeGlobal <TPixel>(Image <TPixel> image, QuantizedFrame <TPixel> quantized, int transparencyIndex, Stream stream) where TPixel : struct, IPixel <TPixel> { var palleteQuantizer = new PaletteQuantizer <TPixel>(quantized.Palette, this.quantizer.Diffuser); for (int i = 0; i < image.Frames.Count; i++) { ImageFrame <TPixel> frame = image.Frames[i]; ImageFrameMetadata metadata = frame.Metadata; GifFrameMetadata frameMetadata = metadata.GetFormatMetadata(GifFormat.Instance); this.WriteGraphicalControlExtension(frameMetadata, transparencyIndex, stream); this.WriteImageDescriptor(frame, false, stream); if (i == 0) { this.WriteImageData(quantized, stream); } else { using (IFrameQuantizer <TPixel> palleteFrameQuantizer = palleteQuantizer.CreateFrameQuantizer(image.GetConfiguration())) using (QuantizedFrame <TPixel> paletteQuantized = palleteFrameQuantizer.QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } } } }
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 PaletteFrameQuantizer <TPixel>(this.configuration, this.quantizer.Options, pixelMap); using IndexedImageFrame <TPixel> paletteQuantized = paletteFrameQuantizer.QuantizeFrame(frame, frame.Bounds()); this.WriteImageData(paletteQuantized, stream); } } }
public void CloneIsDeep() { var metaData = new ImageFrameMetadata(); ImageFrameMetadata clone = metaData.DeepClone(); Assert.False(metaData.GetFormatMetadata(GifFormat.Instance).Equals(clone.GetFormatMetadata(GifFormat.Instance))); }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class. /// </summary> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param> /// <param name="width">The width of the image in pixels.</param> /// <param name="height">The height of the image in pixels.</param> /// <param name="metadata">The metadata.</param> internal ImageFrame(Configuration configuration, int width, int height, ImageFrameMetadata metadata) : base(configuration, width, height, metadata) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); this.PixelBuffer = this.GetConfiguration().MemoryAllocator.Allocate2D <TPixel>(width, height, AllocationOptions.Clean); }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame"/> class. /// </summary> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param> /// <param name="width">The frame width.</param> /// <param name="height">The frame height.</param> /// <param name="metadata">The <see cref="ImageFrameMetadata"/>.</param> protected ImageFrame(Configuration configuration, int width, int height, ImageFrameMetadata metadata) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(metadata, nameof(metadata)); this.configuration = configuration ?? Configuration.Default; this.Width = width; this.Height = height; this.Metadata = metadata; }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame"/> class. /// </summary> /// <param name="configuration">The <see cref="Configuration"/>.</param> /// <param name="width">The width.</param> /// <param name="height">The height.</param> /// <param name="metadata">The <see cref="ImageFrameMetadata"/>.</param> protected ImageFrame(Configuration configuration, int width, int height, ImageFrameMetadata metadata) { Guard.NotNull(configuration, nameof(configuration)); Guard.NotNull(metadata, nameof(metadata)); this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.Width = width; this.Height = height; this.Metadata = metadata; }
/// <summary> /// Decodes the image data from a specified IFD. /// </summary> /// <typeparam name="TPixel">The pixel format.</typeparam> /// <param name="tags">The IFD tags.</param> /// <param name="cancellationToken">The token to monitor cancellation.</param> /// <returns> The tiff frame. </returns> private ImageFrame <TPixel> DecodeFrame <TPixel>(ExifProfile tags, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel <TPixel> { var imageFrameMetaData = new ImageFrameMetadata(); if (!this.ignoreMetadata) { imageFrameMetaData.ExifProfile = tags; } TiffFrameMetadata tiffFrameMetaData = imageFrameMetaData.GetTiffMetadata(); TiffFrameMetadata.Parse(tiffFrameMetaData, tags); this.VerifyAndParse(tags, tiffFrameMetaData); int width = GetImageWidth(tags); int height = GetImageHeight(tags); var frame = new ImageFrame <TPixel>(this.Configuration, width, height, imageFrameMetaData); int rowsPerStrip = tags.GetValue(ExifTag.RowsPerStrip) != null ? (int)tags.GetValue(ExifTag.RowsPerStrip).Value : TiffConstants.RowsPerStripInfinity; var stripOffsetsArray = (Array)tags.GetValueInternal(ExifTag.StripOffsets).GetValue(); var stripByteCountsArray = (Array)tags.GetValueInternal(ExifTag.StripByteCounts).GetValue(); IMemoryOwner <ulong> stripOffsetsMemory = this.ConvertNumbers(stripOffsetsArray, out Span <ulong> stripOffsets); IMemoryOwner <ulong> stripByteCountsMemory = this.ConvertNumbers(stripByteCountsArray, out Span <ulong> stripByteCounts); if (this.PlanarConfiguration == TiffPlanarConfiguration.Planar) { this.DecodeStripsPlanar( frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); } else { this.DecodeStripsChunky( frame, rowsPerStrip, stripOffsets, stripByteCounts, cancellationToken); } stripOffsetsMemory?.Dispose(); stripByteCountsMemory?.Dispose(); return(frame); }
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 static ImageMetadata Create <TPixel>(List <ImageFrame <TPixel> > frames, bool ignoreMetadata, ByteOrder byteOrder, bool isBigTiff) where TPixel : unmanaged, IPixel <TPixel> { if (frames.Count < 1) { TiffThrowHelper.ThrowImageFormatException("Expected at least one frame."); } ImageMetadata imageMetaData = Create(byteOrder, isBigTiff, frames[0].Metadata.ExifProfile); if (!ignoreMetadata) { for (int i = 0; i < frames.Count; i++) { ImageFrame <TPixel> frame = frames[i]; ImageFrameMetadata frameMetaData = frame.Metadata; if (TryGetIptc(frameMetaData.ExifProfile.Values, out byte[] iptcBytes))
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)); }
private void EncodeLocal <TPixel>(Image <TPixel> image, QuantizedFrame <TPixel> quantized, Stream stream) where TPixel : struct, IPixel <TPixel> { ImageFrame <TPixel> previousFrame = null; GifFrameMetadata previousMeta = null; foreach (ImageFrame <TPixel> frame in image.Frames) { ImageFrameMetadata metadata = frame.Metadata; GifFrameMetadata frameMetadata = metadata.GetFormatMetadata(GifFormat.Instance); 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) { quantized = this.quantizer.CreateFrameQuantizer <TPixel>( image.GetConfiguration(), frameMetadata.ColorTableLength).QuantizeFrame(frame); } else { quantized = this.quantizer.CreateFrameQuantizer <TPixel>(image.GetConfiguration()) .QuantizeFrame(frame); } } 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 static ImageMetadata Create<TPixel>(List<ImageFrame<TPixel>> frames, bool ignoreMetadata, ByteOrder byteOrder) where TPixel : unmanaged, IPixel<TPixel> { if (frames.Count < 1) { TiffThrowHelper.ThrowImageFormatException("Expected at least one frame."); } var imageMetaData = new ImageMetadata(); ExifProfile exifProfileRootFrame = frames[0].Metadata.ExifProfile; SetResolution(imageMetaData, exifProfileRootFrame); TiffMetadata tiffMetadata = imageMetaData.GetTiffMetadata(); tiffMetadata.ByteOrder = byteOrder; if (!ignoreMetadata) { for (int i = 0; i < frames.Count; i++) { ImageFrame<TPixel> frame = frames[i]; ImageFrameMetadata frameMetaData = frame.Metadata; if (TryGetIptc(frameMetaData.ExifProfile.Values, out byte[] iptcBytes))
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class wrapping an existing buffer. /// </summary> /// <param name="configuration">The configuration providing initialization code which allows extending the library.</param> /// <param name="width">The width of the image in pixels.</param> /// <param name="height">The height of the image in pixels.</param> /// <param name="memorySource">The memory source.</param> /// <param name="metadata">The metadata.</param> internal ImageFrame(Configuration configuration, int width, int height, MemoryGroup <TPixel> memorySource, ImageFrameMetadata metadata) : base(configuration, width, height, metadata) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); this.PixelBuffer = new Buffer2D <TPixel>(memorySource, width, height); }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class. /// </summary> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param> /// <param name="width">The width of the image in pixels.</param> /// <param name="height">The height of the image in pixels.</param> /// <param name="backgroundColor">The color to clear the image with.</param> /// <param name="metadata">The metadata.</param> internal ImageFrame(Configuration configuration, int width, int height, TPixel backgroundColor, ImageFrameMetadata metadata) { Guard.NotNull(configuration, nameof(configuration)); Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D <TPixel>(width, height); this.Metadata = metadata ?? new ImageFrameMetadata(); this.Clear(configuration.GetParallelOptions(), backgroundColor); }
/// <summary> /// Gets the tiff format specific metadata for the image frame. /// </summary> /// <param name="metadata">The metadata this method extends.</param> /// <returns>The <see cref="TiffFrameMetadata"/>.</returns> public static TiffFrameMetadata GetTiffMetadata(this ImageFrameMetadata metadata) => metadata.GetFormatMetadata(TiffFormat.Instance);
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class. /// </summary> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param> /// <param name="width">The width of the image in pixels.</param> /// <param name="height">The height of the image in pixels.</param> /// <param name="backgroundColor">The color to clear the image with.</param> /// <param name="metadata">The metadata.</param> internal ImageFrame(Configuration configuration, int width, int height, TPixel backgroundColor, ImageFrameMetadata metadata) : base(configuration, width, height, metadata) { Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); this.PixelBuffer = this.MemoryAllocator.Allocate2D <TPixel>(width, height); this.Clear(backgroundColor); }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class wrapping an existing buffer. /// </summary> /// <param name="configuration">The configuration providing initialization code which allows extending the library.</param> /// <param name="width">The width of the image in pixels.</param> /// <param name="height">The height of the image in pixels.</param> /// <param name="memorySource">The memory source.</param> /// <param name="metadata">The metadata.</param> internal ImageFrame(Configuration configuration, int width, int height, MemorySource <TPixel> memorySource, ImageFrameMetadata metadata) { Guard.NotNull(configuration, nameof(configuration)); Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); Guard.NotNull(metadata, nameof(metadata)); this.Configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = new Buffer2D <TPixel>(memorySource, width, height); this.Metadata = metadata; }
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class. /// </summary> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param> /// <param name="size">The <see cref="Size"/> of the frame.</param> /// <param name="metadata">The metadata.</param> internal ImageFrame(Configuration configuration, Size size, ImageFrameMetadata metadata) : this(configuration, size.Width, size.Height, metadata) { }
/// <summary> /// Gets the gif format specific metadata for the image frame. /// </summary> /// <param name="metadata">The metadata this method extends.</param> /// <returns>The <see cref="GifFrameMetadata"/>.</returns> public static GifFrameMetadata GetGifMetadata(this ImageFrameMetadata metadata) => metadata.GetFormatMetadata(GifFormat.Instance);
/// <summary> /// Initializes a new instance of the <see cref="ImageFrame{TPixel}" /> class. /// </summary> /// <param name="configuration">The configuration which allows altering default behaviour or extending the library.</param> /// <param name="width">The width of the image in pixels.</param> /// <param name="height">The height of the image in pixels.</param> /// <param name="metadata">The metadata.</param> internal ImageFrame(Configuration configuration, int width, int height, ImageFrameMetadata metadata) : this(configuration, width, height, default(TPixel), metadata) { }