From 7ea3238d833032745e0c24e666f3b6d61f3e831a Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 5 Feb 2017 11:44:30 +0100 Subject: [PATCH 1/6] Moved the meta data of the image to a new MetaData property. --- ImageSharp.ruleset | 1 + src/ImageSharp.Formats.Gif/GifDecoderCore.cs | 4 +- src/ImageSharp.Formats.Gif/GifEncoderCore.cs | 4 +- .../JpegDecoderCore.cs | 6 +- src/ImageSharp.Formats.Jpeg/JpegEncoder.cs | 4 +- .../JpegEncoderCore.cs | 4 +- src/ImageSharp.Formats.Png/PngDecoderCore.cs | 8 +- src/ImageSharp.Formats.Png/PngEncoderCore.cs | 12 +- .../Transforms/AutoOrient.cs | 6 +- src/ImageSharp/Image/IImage.cs | 25 ++++ src/ImageSharp/Image/IImageBase.cs | 10 +- src/ImageSharp/Image/ImageBase{TColor}.cs | 14 +- src/ImageSharp/Image/ImageFrame{TColor}.cs | 7 +- src/ImageSharp/Image/Image{TColor}.cs | 113 +++------------ src/ImageSharp/Metadata/ImageMetaData.cs | 130 ++++++++++++++++++ .../{Image => Metadata}/ImageProperty.cs | 16 +++ .../Profiles/Exif/ExifDataType.cs | 0 .../{ => Metadata}/Profiles/Exif/ExifParts.cs | 0 .../Profiles/Exif/ExifProfile.cs | 0 .../Profiles/Exif/ExifReader.cs | 0 .../{ => Metadata}/Profiles/Exif/ExifTag.cs | 0 .../Exif/ExifTagDescriptionAttribute.cs | 0 .../{ => Metadata}/Profiles/Exif/ExifValue.cs | 0 .../Profiles/Exif/ExifWriter.cs | 0 .../{ => Metadata}/Profiles/Exif/README.md | 0 .../Formats/GeneralFormatTests.cs | 4 +- .../Formats/Jpg/JpegEncoderTests.cs | 4 +- .../ImageSharp.Tests/Formats/Png/PngTests.cs | 2 +- .../{Image => Metadata}/ImagePropertyTests.cs | 0 .../Profiles/Exif/ExifProfileTests.cs | 90 ++++++------ .../Exif/ExifTagDescriptionAttributeTests.cs | 0 .../Profiles/Exif/ExifValueTests.cs | 2 +- .../Processors/Filters/AutoOrientTests.cs | 4 +- 33 files changed, 282 insertions(+), 188 deletions(-) create mode 100644 src/ImageSharp/Image/IImage.cs create mode 100644 src/ImageSharp/Metadata/ImageMetaData.cs rename src/ImageSharp/{Image => Metadata}/ImageProperty.cs (91%) rename src/ImageSharp/{ => Metadata}/Profiles/Exif/ExifDataType.cs (100%) rename src/ImageSharp/{ => Metadata}/Profiles/Exif/ExifParts.cs (100%) rename src/ImageSharp/{ => Metadata}/Profiles/Exif/ExifProfile.cs (100%) rename src/ImageSharp/{ => Metadata}/Profiles/Exif/ExifReader.cs (100%) rename src/ImageSharp/{ => Metadata}/Profiles/Exif/ExifTag.cs (100%) rename src/ImageSharp/{ => Metadata}/Profiles/Exif/ExifTagDescriptionAttribute.cs (100%) rename src/ImageSharp/{ => Metadata}/Profiles/Exif/ExifValue.cs (100%) rename src/ImageSharp/{ => Metadata}/Profiles/Exif/ExifWriter.cs (100%) rename src/ImageSharp/{ => Metadata}/Profiles/Exif/README.md (100%) rename tests/ImageSharp.Tests/{Image => Metadata}/ImagePropertyTests.cs (100%) rename tests/ImageSharp.Tests/{ => Metadata}/Profiles/Exif/ExifProfileTests.cs (68%) rename tests/ImageSharp.Tests/{ => Metadata}/Profiles/Exif/ExifTagDescriptionAttributeTests.cs (100%) rename tests/ImageSharp.Tests/{ => Metadata}/Profiles/Exif/ExifValueTests.cs (96%) diff --git a/ImageSharp.ruleset b/ImageSharp.ruleset index 554dc16dd..2daf6243a 100644 --- a/ImageSharp.ruleset +++ b/ImageSharp.ruleset @@ -1,6 +1,7 @@  + diff --git a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs index 2be8aed37..9c367c15a 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs @@ -239,7 +239,7 @@ namespace ImageSharp.Formats try { this.currentStream.Read(flagBuffer, 0, flag); - this.decodedImage.Properties.Add(new ImageProperty("Comments", BitConverter.ToString(flagBuffer, 0, flag))); + this.decodedImage.MetaData.Properties.Add(new ImageProperty("Comments", BitConverter.ToString(flagBuffer, 0, flag))); } finally { @@ -323,7 +323,7 @@ namespace ImageSharp.Formats { image = this.decodedImage; - image.Quality = colorTableLength / 3; + this.decodedImage.MetaData.Quality = colorTableLength / 3; // This initializes the image to become fully transparent because the alpha channel is zero. image.InitPixels(imageWidth, imageHeight); diff --git a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs index e5b8ba08a..c5923c1a5 100644 --- a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs @@ -65,7 +65,7 @@ namespace ImageSharp.Formats EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); // Ensure that quality can be set but has a fallback. - int quality = this.Quality > 0 ? this.Quality : image.Quality; + int quality = this.Quality > 0 ? this.Quality : image.MetaData.Quality; this.Quality = quality > 0 ? quality.Clamp(1, 256) : 256; // Get the number of bits. @@ -91,7 +91,7 @@ namespace ImageSharp.Formats // Write additional frames. if (image.Frames.Any()) { - this.WriteApplicationExtension(writer, image.RepeatCount, image.Frames.Count); + this.WriteApplicationExtension(writer, image.MetaData.RepeatCount, image.Frames.Count); // ReSharper disable once ForCanBeConvertedToForeach for (int i = 0; i < image.Frames.Count; i++) diff --git a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs index 1fd963292..9050c20e1 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs @@ -547,8 +547,8 @@ namespace ImageSharp.Formats { if (this.isJfif && this.horizontalResolution > 0 && this.verticalResolution > 0) { - image.HorizontalResolution = this.horizontalResolution; - image.VerticalResolution = this.verticalResolution; + image.MetaData.HorizontalResolution = this.horizontalResolution; + image.MetaData.VerticalResolution = this.verticalResolution; } } @@ -951,7 +951,7 @@ namespace ImageSharp.Formats if (profile[0] == 'E' && profile[1] == 'x' && profile[2] == 'i' && profile[3] == 'f' && profile[4] == '\0' && profile[5] == '\0') { - image.ExifProfile = new ExifProfile(profile); + image.MetaData.ExifProfile = new ExifProfile(profile); } } diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs b/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs index 6f404c9bb..e56a9f2e8 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegEncoder.cs @@ -65,9 +65,9 @@ namespace ImageSharp.Formats where TColor : struct, IPackedPixel, IEquatable { // Ensure that quality can be set but has a fallback. - if (image.Quality > 0) + if (image.MetaData.Quality > 0) { - this.Quality = image.Quality; + this.Quality = image.MetaData.Quality; } JpegEncoderCore encode = new JpegEncoderCore(); diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs index 984418dd3..9cc51c777 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs @@ -200,7 +200,7 @@ namespace ImageSharp.Formats int componentCount = 3; // Write the Start Of Image marker. - this.WriteApplicationHeader((short)image.HorizontalResolution, (short)image.VerticalResolution); + this.WriteApplicationHeader((short)image.MetaData.HorizontalResolution, (short)image.MetaData.VerticalResolution); this.WriteProfiles(image); @@ -706,7 +706,7 @@ namespace ImageSharp.Formats private void WriteProfiles(Image image) where TColor : struct, IPackedPixel, IEquatable { - this.WriteProfile(image.ExifProfile); + this.WriteProfile(image.MetaData.ExifProfile); } /// diff --git a/src/ImageSharp.Formats.Png/PngDecoderCore.cs b/src/ImageSharp.Formats.Png/PngDecoderCore.cs index ffc037b62..3eaa8fde3 100644 --- a/src/ImageSharp.Formats.Png/PngDecoderCore.cs +++ b/src/ImageSharp.Formats.Png/PngDecoderCore.cs @@ -174,7 +174,7 @@ namespace ImageSharp.Formats byte[] pal = new byte[currentChunk.Length]; Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length); this.palette = pal; - image.Quality = pal.Length / 3; + image.MetaData.Quality = pal.Length / 3; break; case PngChunkTypes.PaletteAlpha: byte[] alpha = new byte[currentChunk.Length]; @@ -268,8 +268,8 @@ namespace ImageSharp.Formats data.ReverseBytes(4, 4); // 39.3700787 = inches in a meter. - image.HorizontalResolution = BitConverter.ToInt32(data, 0) / 39.3700787d; - image.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d; + image.MetaData.HorizontalResolution = BitConverter.ToInt32(data, 0) / 39.3700787d; + image.MetaData.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d; } /// @@ -777,7 +777,7 @@ namespace ImageSharp.Formats string name = Encoding.Unicode.GetString(data, 0, zeroIndex); string value = Encoding.Unicode.GetString(data, zeroIndex + 1, length - zeroIndex - 1); - image.Properties.Add(new ImageProperty(name, value)); + image.MetaData.Properties.Add(new ImageProperty(name, value)); } /// diff --git a/src/ImageSharp.Formats.Png/PngEncoderCore.cs b/src/ImageSharp.Formats.Png/PngEncoderCore.cs index 2ab42623d..46aa2187b 100644 --- a/src/ImageSharp.Formats.Png/PngEncoderCore.cs +++ b/src/ImageSharp.Formats.Png/PngEncoderCore.cs @@ -126,12 +126,12 @@ namespace ImageSharp.Formats public byte Threshold { get; set; } /// - /// Encodes the image to the specified stream from the . + /// Encodes the image to the specified stream from the . /// /// The pixel format. /// The to encode from. /// The to encode the image data to. - public void Encode(ImageBase image, Stream stream) + public void Encode(Image image, Stream stream) where TColor : struct, IPackedPixel, IEquatable { Guard.NotNull(image, nameof(image)); @@ -153,7 +153,7 @@ namespace ImageSharp.Formats stream.Write(this.chunkDataBuffer, 0, 8); // Ensure that quality can be set but has a fallback. - int quality = this.Quality > 0 ? this.Quality : image.Quality; + int quality = this.Quality > 0 ? this.Quality : image.MetaData.Quality; this.Quality = quality > 0 ? quality.Clamp(1, int.MaxValue) : int.MaxValue; // Set correct color type if the color count is 256 or less. @@ -557,11 +557,11 @@ namespace ImageSharp.Formats where TColor : struct, IPackedPixel, IEquatable { Image image = imageBase as Image; - if (image != null && image.HorizontalResolution > 0 && image.VerticalResolution > 0) + if (image != null && image.MetaData.HorizontalResolution > 0 && image.MetaData.VerticalResolution > 0) { // 39.3700787 = inches in a meter. - int dpmX = (int)Math.Round(image.HorizontalResolution * 39.3700787D); - int dpmY = (int)Math.Round(image.VerticalResolution * 39.3700787D); + int dpmX = (int)Math.Round(image.MetaData.HorizontalResolution * 39.3700787D); + int dpmY = (int)Math.Round(image.MetaData.VerticalResolution * 39.3700787D); WriteInteger(this.chunkDataBuffer, 0, dpmX); WriteInteger(this.chunkDataBuffer, 4, dpmY); diff --git a/src/ImageSharp.Processing/Transforms/AutoOrient.cs b/src/ImageSharp.Processing/Transforms/AutoOrient.cs index 8d86ae814..cb4e72a94 100644 --- a/src/ImageSharp.Processing/Transforms/AutoOrient.cs +++ b/src/ImageSharp.Processing/Transforms/AutoOrient.cs @@ -66,12 +66,12 @@ namespace ImageSharp private static Orientation GetExifOrientation(Image source) where TColor : struct, IPackedPixel, IEquatable { - if (source.ExifProfile == null) + if (source.MetaData.ExifProfile == null) { return Orientation.Unknown; } - ExifValue value = source.ExifProfile.GetValue(ExifTag.Orientation); + ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation); if (value == null) { return Orientation.Unknown; @@ -79,7 +79,7 @@ namespace ImageSharp Orientation orientation = (Orientation)value.Value; - source.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft); + source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft); return orientation; } diff --git a/src/ImageSharp/Image/IImage.cs b/src/ImageSharp/Image/IImage.cs new file mode 100644 index 000000000..55abdb244 --- /dev/null +++ b/src/ImageSharp/Image/IImage.cs @@ -0,0 +1,25 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using Formats; + + /// + /// Encapsulates the basic properties and methods required to manipulate images. + /// + internal interface IImage : IImageBase + { + /// + /// Gets the currently loaded image format. + /// + IImageFormat CurrentImageFormat { get; } + + /// + /// Gets the meta data of the image. + /// + ImageMetaData MetaData { get; } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Image/IImageBase.cs b/src/ImageSharp/Image/IImageBase.cs index 113b94a18..effbd6006 100644 --- a/src/ImageSharp/Image/IImageBase.cs +++ b/src/ImageSharp/Image/IImageBase.cs @@ -15,11 +15,6 @@ namespace ImageSharp /// Rectangle Bounds { get; } - /// - /// Gets or sets the quality of the image. This affects the output quality of lossy image formats. - /// - int Quality { get; set; } - /// /// Gets or sets the frame delay for animated images. /// If not 0, this field specifies the number of hundredths (1/100) of a second to @@ -52,5 +47,10 @@ namespace ImageSharp /// Gets the pixel ratio made up of the width and height. /// double PixelRatio { get; } + + /// + /// Gets the configuration providing initialization code which allows extending the library. + /// + Configuration Configuration { get; } } } \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index b179d1158..6fcd7a3b7 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -110,9 +110,6 @@ namespace ImageSharp /// public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height); - /// - public int Quality { get; set; } - /// public int FrameDelay { get; set; } @@ -181,16 +178,17 @@ namespace ImageSharp } /// - /// Copies the properties from the other . + /// Copies the properties from the other . /// /// - /// The other to copy the properties from. + /// The other to copy the properties from. /// - protected void CopyProperties(ImageBase other) + protected void CopyProperties(IImageBase other) { - this.Configuration = other.Configuration; - this.Quality = other.Quality; + Debug.Assert(other != null); + this.FrameDelay = other.FrameDelay; + this.Configuration = other.Configuration; } /// diff --git a/src/ImageSharp/Image/ImageFrame{TColor}.cs b/src/ImageSharp/Image/ImageFrame{TColor}.cs index 809eca1a4..b06b10bc4 100644 --- a/src/ImageSharp/Image/ImageFrame{TColor}.cs +++ b/src/ImageSharp/Image/ImageFrame{TColor}.cs @@ -55,11 +55,8 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - ImageFrame target = new ImageFrame(this.Width, this.Height, this.Configuration) - { - Quality = this.Quality, - FrameDelay = this.FrameDelay - }; + ImageFrame target = new ImageFrame(this.Width, this.Height, this.Configuration); + target.CopyProperties(this); using (PixelAccessor pixels = this.Lock()) using (PixelAccessor targetPixels = target.Lock()) diff --git a/src/ImageSharp/Image/Image{TColor}.cs b/src/ImageSharp/Image/Image{TColor}.cs index 84bae39cc..7223bc1d8 100644 --- a/src/ImageSharp/Image/Image{TColor}.cs +++ b/src/ImageSharp/Image/Image{TColor}.cs @@ -23,21 +23,9 @@ namespace ImageSharp /// /// The pixel format. [DebuggerDisplay("Image: {Width}x{Height}")] - public class Image : ImageBase + public class Image : ImageBase, IImage where TColor : struct, IPackedPixel, IEquatable { - /// - /// The default horizontal resolution value (dots per inch) in x direction. - /// The default value is 96 dots per inch. - /// - public const double DefaultHorizontalResolution = 96; - - /// - /// The default vertical resolution value (dots per inch) in y direction. - /// The default value is 96 dots per inch. - /// - public const double DefaultVerticalResolution = 96; - /// /// Initializes a new instance of the class /// with the height and the width of the image. @@ -129,18 +117,9 @@ namespace ImageSharp } /// - /// Gets or sets the resolution of the image in x- direction. It is defined as - /// number of dots per inch and should be an positive value. - /// - /// The density of the image in x- direction. - public double HorizontalResolution { get; set; } = DefaultHorizontalResolution; - - /// - /// Gets or sets the resolution of the image in y- direction. It is defined as - /// number of dots per inch and should be an positive value. + /// Gets the meta data of the image. /// - /// The density of the image in y- direction. - public double VerticalResolution { get; set; } = DefaultVerticalResolution; + public ImageMetaData MetaData { get; private set; } = new ImageMetaData(); /// /// Gets the width of the image in inches. It is calculated as the width of the image @@ -152,14 +131,7 @@ namespace ImageSharp { get { - double resolution = this.HorizontalResolution; - - if (resolution <= 0) - { - resolution = DefaultHorizontalResolution; - } - - return this.Width / resolution; + return this.Width / this.MetaData.HorizontalResolution; } } @@ -173,14 +145,7 @@ namespace ImageSharp { get { - double resolution = this.VerticalResolution; - - if (resolution <= 0) - { - resolution = DefaultVerticalResolution; - } - - return this.Height / resolution; + return this.Height / this.MetaData.VerticalResolution; } } @@ -192,34 +157,17 @@ namespace ImageSharp /// public bool IsAnimated => this.Frames.Count > 0; - /// - /// Gets or sets the number of times any animation is repeated. - /// 0 means to repeat indefinitely. - /// - public ushort RepeatCount { get; set; } - /// /// Gets the other frames for the animation. /// /// The list of frame images. public IList> Frames { get; } = new List>(); - /// - /// Gets the list of properties for storing meta information about this image. - /// - /// A list of image properties. - public IList Properties { get; } = new List(); - /// /// Gets the currently loaded image format. /// public IImageFormat CurrentImageFormat { get; internal set; } - /// - /// Gets or sets the Exif profile. - /// - public ExifProfile ExifProfile { get; set; } - /// /// Applies the processor to the image. /// @@ -317,15 +265,8 @@ namespace ImageSharp { scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction(scaleFunc); - Image target = new Image(this.Width, this.Height, this.Configuration) - { - Quality = this.Quality, - FrameDelay = this.FrameDelay, - HorizontalResolution = this.HorizontalResolution, - VerticalResolution = this.VerticalResolution, - CurrentImageFormat = this.CurrentImageFormat, - RepeatCount = this.RepeatCount - }; + Image target = new Image(this.Width, this.Height, this.Configuration); + target.CopyProperties(this); using (PixelAccessor pixels = this.Lock()) using (PixelAccessor targetPixels = target.Lock()) @@ -345,11 +286,6 @@ namespace ImageSharp }); } - if (this.ExifProfile != null) - { - target.ExifProfile = new ExifProfile(this.ExifProfile); - } - for (int i = 0; i < this.Frames.Count; i++) { target.Frames.Add(this.Frames[i].To()); @@ -358,27 +294,6 @@ namespace ImageSharp return target; } - /// - /// Copies the properties from the other . - /// - /// - /// The other to copy the properties from. - /// - internal void CopyProperties(Image other) - { - base.CopyProperties(other); - - this.HorizontalResolution = other.HorizontalResolution; - this.VerticalResolution = other.VerticalResolution; - this.CurrentImageFormat = other.CurrentImageFormat; - this.RepeatCount = other.RepeatCount; - - if (other.ExifProfile != null) - { - this.ExifProfile = new ExifProfile(other.ExifProfile); - } - } - /// /// Creates a new from this instance /// @@ -400,6 +315,20 @@ namespace ImageSharp base.Dispose(disposing); } + /// + /// Copies the properties from the other . + /// + /// + /// The other to copy the properties from. + /// + private void CopyProperties(IImage other) + { + base.CopyProperties(other); + + this.CurrentImageFormat = other.CurrentImageFormat; + this.MetaData = new ImageMetaData(other.MetaData); + } + /// /// Loads the image from the given stream. /// diff --git a/src/ImageSharp/Metadata/ImageMetaData.cs b/src/ImageSharp/Metadata/ImageMetaData.cs new file mode 100644 index 000000000..30bd2c348 --- /dev/null +++ b/src/ImageSharp/Metadata/ImageMetaData.cs @@ -0,0 +1,130 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System.Collections.Generic; + using System.Diagnostics; + + /// + /// Encapsulates the metadata of an image. + /// + public sealed class ImageMetaData + { + /// + /// The default horizontal resolution value (dots per inch) in x direction. + /// The default value is 96 dots per inch. + /// + public const double DefaultHorizontalResolution = 96; + + /// + /// The default vertical resolution value (dots per inch) in y direction. + /// The default value is 96 dots per inch. + /// + public const double DefaultVerticalResolution = 96; + + private double horizontalResolution; + private double verticalResolution; + + /// + /// Initializes a new instance of the class. + /// + internal ImageMetaData() + { + this.horizontalResolution = DefaultHorizontalResolution; + this.verticalResolution = DefaultVerticalResolution; + } + + /// + /// Initializes a new instance of the class + /// by making a copy from other metadata. + /// + /// + /// The other to create this instance from. + /// + internal ImageMetaData(ImageMetaData other) + { + Debug.Assert(other != null); + + this.HorizontalResolution = other.HorizontalResolution; + this.VerticalResolution = other.VerticalResolution; + this.Quality = other.Quality; + + foreach (ImageProperty property in other.Properties) + { + this.Properties.Add(new ImageProperty(property)); + } + + if (other.ExifProfile != null) + { + this.ExifProfile = new ExifProfile(other.ExifProfile); + } + } + + /// + /// Gets or sets the resolution of the image in x- direction. It is defined as + /// number of dots per inch and should be an positive value. + /// + /// The density of the image in x- direction. + public double HorizontalResolution + { + get + { + return this.horizontalResolution; + } + + set + { + if (value >= 0) + { + this.horizontalResolution = value; + } + } + } + + /// + /// Gets or sets the resolution of the image in y- direction. It is defined as + /// number of dots per inch and should be an positive value. + /// + /// The density of the image in y- direction. + public double VerticalResolution + { + get + { + return this.verticalResolution; + } + + set + { + if (value >= 0) + { + this.verticalResolution = value; + } + } + } + + /// + /// Gets or sets the Exif profile. + /// + public ExifProfile ExifProfile { get; set; } + + /// + /// Gets the list of properties for storing meta information about this image. + /// + /// A list of image properties. + public IList Properties { get; } = new List(); + + /// + /// Gets or sets the quality of the image. This affects the output quality of lossy image formats. + /// + public int Quality { get; set; } + + /// + /// Gets or sets the number of times any animation is repeated. + /// 0 means to repeat indefinitely. + /// + public ushort RepeatCount { get; set; } + } +} diff --git a/src/ImageSharp/Image/ImageProperty.cs b/src/ImageSharp/Metadata/ImageProperty.cs similarity index 91% rename from src/ImageSharp/Image/ImageProperty.cs rename to src/ImageSharp/Metadata/ImageProperty.cs index 7fda749e9..c8bd0b23d 100644 --- a/src/ImageSharp/Image/ImageProperty.cs +++ b/src/ImageSharp/Metadata/ImageProperty.cs @@ -6,6 +6,7 @@ namespace ImageSharp { using System; + using System.Diagnostics; /// /// Stores meta information about a image, like the name of the author, @@ -27,6 +28,21 @@ namespace ImageSharp this.Value = value; } + /// + /// Initializes a new instance of the class + /// by making a copy from another property. + /// + /// + /// The other to create this instance from. + /// + internal ImageProperty(ImageProperty other) + { + Debug.Assert(other != null); + + this.Name = other.Name; + this.Value = other.Value; + } + /// /// Gets the name of this indicating which kind of /// information this property stores. diff --git a/src/ImageSharp/Profiles/Exif/ExifDataType.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs similarity index 100% rename from src/ImageSharp/Profiles/Exif/ExifDataType.cs rename to src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs diff --git a/src/ImageSharp/Profiles/Exif/ExifParts.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs similarity index 100% rename from src/ImageSharp/Profiles/Exif/ExifParts.cs rename to src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs diff --git a/src/ImageSharp/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs similarity index 100% rename from src/ImageSharp/Profiles/Exif/ExifProfile.cs rename to src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs diff --git a/src/ImageSharp/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs similarity index 100% rename from src/ImageSharp/Profiles/Exif/ExifReader.cs rename to src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs diff --git a/src/ImageSharp/Profiles/Exif/ExifTag.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifTag.cs similarity index 100% rename from src/ImageSharp/Profiles/Exif/ExifTag.cs rename to src/ImageSharp/Metadata/Profiles/Exif/ExifTag.cs diff --git a/src/ImageSharp/Profiles/Exif/ExifTagDescriptionAttribute.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs similarity index 100% rename from src/ImageSharp/Profiles/Exif/ExifTagDescriptionAttribute.cs rename to src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs diff --git a/src/ImageSharp/Profiles/Exif/ExifValue.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifValue.cs similarity index 100% rename from src/ImageSharp/Profiles/Exif/ExifValue.cs rename to src/ImageSharp/Metadata/Profiles/Exif/ExifValue.cs diff --git a/src/ImageSharp/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs similarity index 100% rename from src/ImageSharp/Profiles/Exif/ExifWriter.cs rename to src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs diff --git a/src/ImageSharp/Profiles/Exif/README.md b/src/ImageSharp/Metadata/Profiles/Exif/README.md similarity index 100% rename from src/ImageSharp/Profiles/Exif/README.md rename to src/ImageSharp/Metadata/Profiles/Exif/README.md diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 6873717ed..97bd34def 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -24,8 +24,8 @@ namespace ImageSharp.Tests { using (FileStream output = File.OpenWrite($"{path}/{file.FileName}")) { - image.VerticalResolution = 150; - image.HorizontalResolution = 150; + image.MetaData.VerticalResolution = 150; + image.MetaData.HorizontalResolution = 150; image.Save(output); } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index 59e5eba5c..ef6671931 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -36,8 +36,8 @@ namespace ImageSharp.Tests { using (Image image = provider.GetImage().Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max })) { - image.Quality = quality; - image.ExifProfile = null; // Reduce the size of the file + image.MetaData.Quality = quality; + image.MetaData.ExifProfile = null; // Reduce the size of the file JpegEncoder encoder = new JpegEncoder { Subsample = subsample, Quality = quality }; provider.Utility.TestName += $"{subsample}_Q{quality}"; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngTests.cs index ae6487ea9..cf485c593 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngTests.cs @@ -27,7 +27,7 @@ namespace ImageSharp.Tests { using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png")) { - image.Quality = 256; + image.MetaData.Quality = 256; image.Save(output, new PngFormat()); } } diff --git a/tests/ImageSharp.Tests/Image/ImagePropertyTests.cs b/tests/ImageSharp.Tests/Metadata/ImagePropertyTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Image/ImagePropertyTests.cs rename to tests/ImageSharp.Tests/Metadata/ImagePropertyTests.cs diff --git a/tests/ImageSharp.Tests/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs similarity index 68% rename from tests/ImageSharp.Tests/Profiles/Exif/ExifProfileTests.cs rename to tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 1900b58c6..61307da20 100644 --- a/tests/ImageSharp.Tests/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs @@ -19,20 +19,18 @@ namespace ImageSharp.Tests { Image image = TestFile.Create(TestImages.Jpeg.Baseline.Calliphora).CreateImage(); - Assert.Null(image.ExifProfile); + Assert.Null(image.MetaData.ExifProfile); - image.ExifProfile = new ExifProfile(); - image.ExifProfile.SetValue(ExifTag.Copyright, "Dirk Lemstra"); + image.MetaData.ExifProfile = new ExifProfile(); + image.MetaData.ExifProfile.SetValue(ExifTag.Copyright, "Dirk Lemstra"); image = WriteAndRead(image); - Assert.NotNull(image.ExifProfile); - Assert.Equal(1, image.ExifProfile.Values.Count()); + Assert.NotNull(image.MetaData.ExifProfile); + Assert.Equal(1, image.MetaData.ExifProfile.Values.Count()); - ExifValue value = image.ExifProfile.Values.FirstOrDefault(val => val.Tag == ExifTag.Copyright); + ExifValue value = image.MetaData.ExifProfile.Values.FirstOrDefault(val => val.Tag == ExifTag.Copyright); TestValue(value, "Dirk Lemstra"); - - } [Fact] @@ -70,14 +68,14 @@ namespace ImageSharp.Tests profile.SetValue(ExifTag.ExposureTime, new Rational(exposureTime)); Image image = new Image(1, 1); - image.ExifProfile = profile; + image.MetaData.ExifProfile = profile; image.SaveAsJpeg(memStream); memStream.Position = 0; image = new Image(memStream); - profile = image.ExifProfile; + profile = image.MetaData.ExifProfile; Assert.NotNull(profile); ExifValue value = profile.GetValue(ExifTag.ExposureTime); @@ -88,14 +86,14 @@ namespace ImageSharp.Tests profile = GetExifProfile(); profile.SetValue(ExifTag.ExposureTime, new Rational(exposureTime, true)); - image.ExifProfile = profile; + image.MetaData.ExifProfile = profile; image.SaveAsJpeg(memStream); memStream.Position = 0; image = new Image(memStream); - profile = image.ExifProfile; + profile = image.MetaData.ExifProfile; Assert.NotNull(profile); value = profile.GetValue(ExifTag.ExposureTime); @@ -107,24 +105,24 @@ namespace ImageSharp.Tests public void ReadWriteInfinity() { Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage(); - image.ExifProfile.SetValue(ExifTag.ExposureBiasValue, new SignedRational(double.PositiveInfinity)); + image.MetaData.ExifProfile.SetValue(ExifTag.ExposureBiasValue, new SignedRational(double.PositiveInfinity)); image = WriteAndRead(image); - ExifValue value = image.ExifProfile.GetValue(ExifTag.ExposureBiasValue); + ExifValue value = image.MetaData.ExifProfile.GetValue(ExifTag.ExposureBiasValue); Assert.NotNull(value); Assert.Equal(new SignedRational(double.PositiveInfinity), value.Value); - image.ExifProfile.SetValue(ExifTag.ExposureBiasValue, new SignedRational(double.NegativeInfinity)); + image.MetaData.ExifProfile.SetValue(ExifTag.ExposureBiasValue, new SignedRational(double.NegativeInfinity)); image = WriteAndRead(image); - value = image.ExifProfile.GetValue(ExifTag.ExposureBiasValue); + value = image.MetaData.ExifProfile.GetValue(ExifTag.ExposureBiasValue); Assert.NotNull(value); Assert.Equal(new SignedRational(double.NegativeInfinity), value.Value); - image.ExifProfile.SetValue(ExifTag.FlashEnergy, new Rational(double.NegativeInfinity)); + image.MetaData.ExifProfile.SetValue(ExifTag.FlashEnergy, new Rational(double.NegativeInfinity)); image = WriteAndRead(image); - value = image.ExifProfile.GetValue(ExifTag.FlashEnergy); + value = image.MetaData.ExifProfile.GetValue(ExifTag.FlashEnergy); Assert.NotNull(value); Assert.Equal(new Rational(double.PositiveInfinity), value.Value); } @@ -135,71 +133,71 @@ namespace ImageSharp.Tests Rational[] latitude = new Rational[] { new Rational(12.3), new Rational(4.56), new Rational(789.0) }; Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage(); - image.ExifProfile.SetValue(ExifTag.Software, "ImageSharp"); + image.MetaData.ExifProfile.SetValue(ExifTag.Software, "ImageSharp"); - ExifValue value = image.ExifProfile.GetValue(ExifTag.Software); + ExifValue value = image.MetaData.ExifProfile.GetValue(ExifTag.Software); TestValue(value, "ImageSharp"); Assert.Throws(() => { value.Value = 15; }); - image.ExifProfile.SetValue(ExifTag.ShutterSpeedValue, new SignedRational(75.55)); + image.MetaData.ExifProfile.SetValue(ExifTag.ShutterSpeedValue, new SignedRational(75.55)); - value = image.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); + value = image.MetaData.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); TestValue(value, new SignedRational(7555, 100)); Assert.Throws(() => { value.Value = 75; }); - image.ExifProfile.SetValue(ExifTag.XResolution, new Rational(150.0)); + image.MetaData.ExifProfile.SetValue(ExifTag.XResolution, new Rational(150.0)); - value = image.ExifProfile.GetValue(ExifTag.XResolution); + value = image.MetaData.ExifProfile.GetValue(ExifTag.XResolution); TestValue(value, new Rational(150, 1)); Assert.Throws(() => { value.Value = "ImageSharp"; }); - image.ExifProfile.SetValue(ExifTag.ReferenceBlackWhite, null); + image.MetaData.ExifProfile.SetValue(ExifTag.ReferenceBlackWhite, null); - value = image.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); + value = image.MetaData.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); TestValue(value, (string)null); - image.ExifProfile.SetValue(ExifTag.GPSLatitude, latitude); + image.MetaData.ExifProfile.SetValue(ExifTag.GPSLatitude, latitude); - value = image.ExifProfile.GetValue(ExifTag.GPSLatitude); + value = image.MetaData.ExifProfile.GetValue(ExifTag.GPSLatitude); TestValue(value, latitude); image = WriteAndRead(image); - Assert.NotNull(image.ExifProfile); - Assert.Equal(17, image.ExifProfile.Values.Count()); + Assert.NotNull(image.MetaData.ExifProfile); + Assert.Equal(17, image.MetaData.ExifProfile.Values.Count()); - value = image.ExifProfile.GetValue(ExifTag.Software); + value = image.MetaData.ExifProfile.GetValue(ExifTag.Software); TestValue(value, "ImageSharp"); - value = image.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); + value = image.MetaData.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); TestValue(value, new SignedRational(75.55)); - value = image.ExifProfile.GetValue(ExifTag.XResolution); + value = image.MetaData.ExifProfile.GetValue(ExifTag.XResolution); TestValue(value, new Rational(150.0)); - value = image.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); + value = image.MetaData.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); Assert.Null(value); - value = image.ExifProfile.GetValue(ExifTag.GPSLatitude); + value = image.MetaData.ExifProfile.GetValue(ExifTag.GPSLatitude); TestValue(value, latitude); - image.ExifProfile.Parts = ExifParts.ExifTags; + image.MetaData.ExifProfile.Parts = ExifParts.ExifTags; image = WriteAndRead(image); - Assert.NotNull(image.ExifProfile); - Assert.Equal(8, image.ExifProfile.Values.Count()); + Assert.NotNull(image.MetaData.ExifProfile); + Assert.Equal(8, image.MetaData.ExifProfile.Values.Count()); - Assert.NotNull(image.ExifProfile.GetValue(ExifTag.ColorSpace)); - Assert.True(image.ExifProfile.RemoveValue(ExifTag.ColorSpace)); - Assert.False(image.ExifProfile.RemoveValue(ExifTag.ColorSpace)); - Assert.Null(image.ExifProfile.GetValue(ExifTag.ColorSpace)); + Assert.NotNull(image.MetaData.ExifProfile.GetValue(ExifTag.ColorSpace)); + Assert.True(image.MetaData.ExifProfile.RemoveValue(ExifTag.ColorSpace)); + Assert.False(image.MetaData.ExifProfile.RemoveValue(ExifTag.ColorSpace)); + Assert.Null(image.MetaData.ExifProfile.GetValue(ExifTag.ColorSpace)); - Assert.Equal(7, image.ExifProfile.Values.Count()); + Assert.Equal(7, image.MetaData.ExifProfile.Values.Count()); } [Fact] @@ -225,8 +223,8 @@ namespace ImageSharp.Tests } Image image = new Image(100, 100); - image.ExifProfile = new ExifProfile(); - image.ExifProfile.SetValue(ExifTag.ImageDescription, junk.ToString()); + image.MetaData.ExifProfile = new ExifProfile(); + image.MetaData.ExifProfile.SetValue(ExifTag.ImageDescription, junk.ToString()); using (MemoryStream memStream = new MemoryStream()) { @@ -238,7 +236,7 @@ namespace ImageSharp.Tests { Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage(); - ExifProfile profile = image.ExifProfile; + ExifProfile profile = image.MetaData.ExifProfile; Assert.NotNull(profile); return profile; diff --git a/tests/ImageSharp.Tests/Profiles/Exif/ExifTagDescriptionAttributeTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Profiles/Exif/ExifTagDescriptionAttributeTests.cs rename to tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs diff --git a/tests/ImageSharp.Tests/Profiles/Exif/ExifValueTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs similarity index 96% rename from tests/ImageSharp.Tests/Profiles/Exif/ExifValueTests.cs rename to tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs index e777d9e3b..2014d08dc 100644 --- a/tests/ImageSharp.Tests/Profiles/Exif/ExifValueTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs @@ -15,7 +15,7 @@ namespace ImageSharp.Tests ExifProfile profile; using (Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage()) { - profile = image.ExifProfile; + profile = image.MetaData.ExifProfile; } Assert.NotNull(profile); diff --git a/tests/ImageSharp.Tests/Processors/Filters/AutoOrientTests.cs b/tests/ImageSharp.Tests/Processors/Filters/AutoOrientTests.cs index 499bdff82..ef183480c 100644 --- a/tests/ImageSharp.Tests/Processors/Filters/AutoOrientTests.cs +++ b/tests/ImageSharp.Tests/Processors/Filters/AutoOrientTests.cs @@ -35,8 +35,8 @@ namespace ImageSharp.Tests using (Image image = file.CreateImage()) { - image.ExifProfile = new ExifProfile(); - image.ExifProfile.SetValue(ExifTag.Orientation, orientation); + image.MetaData.ExifProfile = new ExifProfile(); + image.MetaData.ExifProfile.SetValue(ExifTag.Orientation, orientation); using (FileStream before = File.OpenWrite($"{path}/before-{file.FileName}")) using (FileStream after = File.OpenWrite($"{path}/after-{file.FileName}")) From 42b2b666e08f610e9a4eb7db9f1622a565b35663 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 5 Feb 2017 12:18:03 +0100 Subject: [PATCH 2/6] Added metadata class for image frames. --- src/ImageSharp.Formats.Gif/GifDecoderCore.cs | 27 ++++++++---- src/ImageSharp.Formats.Gif/GifEncoderCore.cs | 31 ++++++++++++- src/ImageSharp/Image/IImageBase.cs | 8 ---- src/ImageSharp/Image/IImageFrame.cs | 18 ++++++++ src/ImageSharp/Image/ImageBase{TColor}.cs | 4 -- src/ImageSharp/Image/ImageFrame{TColor}.cs | 20 ++++++++- src/ImageSharp/Metadata/IMetaData.cs | 21 +++++++++ src/ImageSharp/Metadata/ImageFrameMetaData.cs | 44 +++++++++++++++++++ src/ImageSharp/Metadata/ImageMetaData.cs | 12 ++++- .../Metadata/ImageFrameMetaDataTests.cs | 26 +++++++++++ .../Metadata/ImageMetaDataTests.cs | 42 ++++++++++++++++++ 11 files changed, 229 insertions(+), 24 deletions(-) create mode 100644 src/ImageSharp/Image/IImageFrame.cs create mode 100644 src/ImageSharp/Metadata/IMetaData.cs create mode 100644 src/ImageSharp/Metadata/ImageFrameMetaData.cs create mode 100644 tests/ImageSharp.Tests/Metadata/ImageFrameMetaDataTests.cs create mode 100644 tests/ImageSharp.Tests/Metadata/ImageMetaDataTests.cs diff --git a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs index 9c367c15a..e6f7b6136 100644 --- a/src/ImageSharp.Formats.Gif/GifDecoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifDecoderCore.cs @@ -321,12 +321,14 @@ namespace ImageSharp.Formats if (this.previousFrame == null) { - image = this.decodedImage; - this.decodedImage.MetaData.Quality = colorTableLength / 3; // This initializes the image to become fully transparent because the alpha channel is zero. - image.InitPixels(imageWidth, imageHeight); + this.decodedImage.InitPixels(imageWidth, imageHeight); + + this.SetFrameDelay(this.decodedImage.MetaData); + + image = this.decodedImage; } else { @@ -338,6 +340,8 @@ namespace ImageSharp.Formats currentFrame = this.previousFrame.Clone(); + this.SetFrameDelay(currentFrame.MetaData); + image = currentFrame; this.RestoreToBackground(image); @@ -345,11 +349,6 @@ namespace ImageSharp.Formats this.decodedImage.Frames.Add(currentFrame); } - if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0) - { - image.FrameDelay = this.graphicsControlExtension.DelayTime; - } - int i = 0; int interlacePass = 0; // The interlace pass int interlaceIncrement = 8; // The interlacing line increment @@ -465,5 +464,17 @@ namespace ImageSharp.Formats this.restoreArea = null; } + + /// + /// Sets the frame delay in the metadata. + /// + /// The meta data. + private void SetFrameDelay(IMetaData metaData) + { + if (this.graphicsControlExtension != null && this.graphicsControlExtension.DelayTime > 0) + { + metaData.FrameDelay = this.graphicsControlExtension.DelayTime; + } + } } } \ No newline at end of file diff --git a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs index c5923c1a5..80c9ee36b 100644 --- a/src/ImageSharp.Formats.Gif/GifEncoderCore.cs +++ b/src/ImageSharp.Formats.Gif/GifEncoderCore.cs @@ -229,14 +229,41 @@ namespace ImageSharp.Formats } } + /// + /// Writes the graphics control extension to the stream. + /// + /// The pixel format. + /// The to encode. + /// The stream to write to. + /// The index of the color in the color palette to make transparent. + private void WriteGraphicalControlExtension(Image image, EndianBinaryWriter writer, int transparencyIndex) + where TColor : struct, IPackedPixel, IEquatable + { + this.WriteGraphicalControlExtension(image, image.MetaData, writer, transparencyIndex); + } + + /// + /// Writes the graphics control extension to the stream. + /// + /// The pixel format. + /// The to encode. + /// The stream to write to. + /// The index of the color in the color palette to make transparent. + private void WriteGraphicalControlExtension(ImageFrame imageFrame, EndianBinaryWriter writer, int transparencyIndex) + where TColor : struct, IPackedPixel, IEquatable + { + this.WriteGraphicalControlExtension(imageFrame, imageFrame.MetaData, writer, transparencyIndex); + } + /// /// Writes the graphics control extension to the stream. /// /// The pixel format. /// The to encode. + /// The metadata of the image or frame. /// The stream to write to. /// The index of the color in the color palette to make transparent. - private void WriteGraphicalControlExtension(ImageBase image, EndianBinaryWriter writer, int transparencyIndex) + private void WriteGraphicalControlExtension(ImageBase image, IMetaData metaData, EndianBinaryWriter writer, int transparencyIndex) where TColor : struct, IPackedPixel, IEquatable { // TODO: Check transparency logic. @@ -250,7 +277,7 @@ namespace ImageSharp.Formats DisposalMethod = disposalMethod, TransparencyFlag = hasTransparent, TransparencyIndex = transparencyIndex, - DelayTime = image.FrameDelay + DelayTime = metaData.FrameDelay }; // Write the intro. diff --git a/src/ImageSharp/Image/IImageBase.cs b/src/ImageSharp/Image/IImageBase.cs index effbd6006..707fea235 100644 --- a/src/ImageSharp/Image/IImageBase.cs +++ b/src/ImageSharp/Image/IImageBase.cs @@ -15,14 +15,6 @@ namespace ImageSharp /// Rectangle Bounds { get; } - /// - /// Gets or sets the frame delay for animated images. - /// If not 0, this field specifies the number of hundredths (1/100) of a second to - /// wait before continuing with the processing of the Data Stream. - /// The clock starts ticking immediately after the graphic is rendered. - /// - int FrameDelay { get; set; } - /// /// Gets or sets the maximum allowable width in pixels. /// diff --git a/src/ImageSharp/Image/IImageFrame.cs b/src/ImageSharp/Image/IImageFrame.cs new file mode 100644 index 000000000..bf3261d93 --- /dev/null +++ b/src/ImageSharp/Image/IImageFrame.cs @@ -0,0 +1,18 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + /// + /// Encapsulates the basic properties and methods required to manipulate images. + /// + internal interface IImageFrame : IImageBase + { + /// + /// Gets the meta data of the image. + /// + ImageFrameMetaData MetaData { get; } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Image/ImageBase{TColor}.cs b/src/ImageSharp/Image/ImageBase{TColor}.cs index 6fcd7a3b7..fd82f7730 100644 --- a/src/ImageSharp/Image/ImageBase{TColor}.cs +++ b/src/ImageSharp/Image/ImageBase{TColor}.cs @@ -110,9 +110,6 @@ namespace ImageSharp /// public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height); - /// - public int FrameDelay { get; set; } - /// /// Gets the configuration providing initialization code which allows extending the library. /// @@ -187,7 +184,6 @@ namespace ImageSharp { Debug.Assert(other != null); - this.FrameDelay = other.FrameDelay; this.Configuration = other.Configuration; } diff --git a/src/ImageSharp/Image/ImageFrame{TColor}.cs b/src/ImageSharp/Image/ImageFrame{TColor}.cs index b06b10bc4..02e5b7161 100644 --- a/src/ImageSharp/Image/ImageFrame{TColor}.cs +++ b/src/ImageSharp/Image/ImageFrame{TColor}.cs @@ -13,7 +13,7 @@ namespace ImageSharp /// Represents a single frame in a animation. /// /// The pixel format. - public class ImageFrame : ImageBase + public class ImageFrame : ImageBase, IImageFrame where TColor : struct, IPackedPixel, IEquatable { /// @@ -38,6 +38,11 @@ namespace ImageSharp { } + /// + /// Gets the meta data of the frame. + /// + public ImageFrameMetaData MetaData { get; private set; } = new ImageFrameMetaData(); + /// public override string ToString() { @@ -87,5 +92,18 @@ namespace ImageSharp { return new ImageFrame(this); } + + /// + /// Copies the properties from the other . + /// + /// + /// The other to copy the properties from. + /// + private void CopyProperties(IImageFrame other) + { + base.CopyProperties(other); + + this.MetaData = new ImageFrameMetaData(other.MetaData); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Metadata/IMetaData.cs b/src/ImageSharp/Metadata/IMetaData.cs new file mode 100644 index 000000000..38fd31349 --- /dev/null +++ b/src/ImageSharp/Metadata/IMetaData.cs @@ -0,0 +1,21 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + /// + /// Encapsulates the metadata of an image frame. + /// + internal interface IMetaData + { + /// + /// Gets or sets the frame delay for animated images. + /// If not 0, this field specifies the number of hundredths (1/100) of a second to + /// wait before continuing with the processing of the Data Stream. + /// The clock starts ticking immediately after the graphic is rendered. + /// + int FrameDelay { get; set; } + } +} diff --git a/src/ImageSharp/Metadata/ImageFrameMetaData.cs b/src/ImageSharp/Metadata/ImageFrameMetaData.cs new file mode 100644 index 000000000..c2277686f --- /dev/null +++ b/src/ImageSharp/Metadata/ImageFrameMetaData.cs @@ -0,0 +1,44 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp +{ + using System.Diagnostics; + + /// + /// Encapsulates the metadata of an image frame. + /// + public sealed class ImageFrameMetaData : IMetaData + { + /// + /// Initializes a new instance of the class. + /// + internal ImageFrameMetaData() + { + } + + /// + /// Initializes a new instance of the class + /// by making a copy from other metadata. + /// + /// + /// The other to create this instance from. + /// + internal ImageFrameMetaData(ImageFrameMetaData other) + { + Debug.Assert(other != null); + + this.FrameDelay = other.FrameDelay; + } + + /// + /// Gets or sets the frame delay for animated images. + /// If not 0, this field specifies the number of hundredths (1/100) of a second to + /// wait before continuing with the processing of the Data Stream. + /// The clock starts ticking immediately after the graphic is rendered. + /// + public int FrameDelay { get; set; } + } +} diff --git a/src/ImageSharp/Metadata/ImageMetaData.cs b/src/ImageSharp/Metadata/ImageMetaData.cs index 30bd2c348..a38899840 100644 --- a/src/ImageSharp/Metadata/ImageMetaData.cs +++ b/src/ImageSharp/Metadata/ImageMetaData.cs @@ -11,7 +11,7 @@ namespace ImageSharp /// /// Encapsulates the metadata of an image. /// - public sealed class ImageMetaData + public sealed class ImageMetaData : IMetaData { /// /// The default horizontal resolution value (dots per inch) in x direction. @@ -51,6 +51,8 @@ namespace ImageSharp this.HorizontalResolution = other.HorizontalResolution; this.VerticalResolution = other.VerticalResolution; this.Quality = other.Quality; + this.FrameDelay = other.FrameDelay; + this.RepeatCount = other.RepeatCount; foreach (ImageProperty property in other.Properties) { @@ -110,6 +112,14 @@ namespace ImageSharp /// public ExifProfile ExifProfile { get; set; } + /// + /// Gets or sets the frame delay for animated images. + /// If not 0, this field specifies the number of hundredths (1/100) of a second to + /// wait before continuing with the processing of the Data Stream. + /// The clock starts ticking immediately after the graphic is rendered. + /// + public int FrameDelay { get; set; } + /// /// Gets the list of properties for storing meta information about this image. /// diff --git a/tests/ImageSharp.Tests/Metadata/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/Metadata/ImageFrameMetaDataTests.cs new file mode 100644 index 000000000..24dd2eac5 --- /dev/null +++ b/tests/ImageSharp.Tests/Metadata/ImageFrameMetaDataTests.cs @@ -0,0 +1,26 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using Xunit; + + /// + /// Tests the class. + /// + public class ImageFrameMetaDataTests + { + [Fact] + public void ConstructorImageFrameMetaData() + { + ImageFrameMetaData metaData = new ImageFrameMetaData(); + metaData.FrameDelay = 42; + + ImageFrameMetaData clone = new ImageFrameMetaData(metaData); + + Assert.Equal(42, clone.FrameDelay); + } + } +} diff --git a/tests/ImageSharp.Tests/Metadata/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/Metadata/ImageMetaDataTests.cs new file mode 100644 index 000000000..9034b88c0 --- /dev/null +++ b/tests/ImageSharp.Tests/Metadata/ImageMetaDataTests.cs @@ -0,0 +1,42 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageSharp.Tests +{ + using Xunit; + + /// + /// Tests the class. + /// + public class ImageMetaDataTests + { + [Fact] + public void ConstructorImageMetaData() + { + ImageMetaData metaData = new ImageMetaData(); + + ExifProfile exifProfile = new ExifProfile(); + ImageProperty imageProperty = new ImageProperty("name", "value"); + + metaData.ExifProfile = exifProfile; + metaData.FrameDelay = 42; + metaData.HorizontalResolution = 4; + metaData.VerticalResolution = 2; + metaData.Properties.Add(imageProperty); + metaData.Quality = 24; + metaData.RepeatCount = 1; + + ImageMetaData clone = new ImageMetaData(metaData); + + Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); + Assert.Equal(42, clone.FrameDelay); + Assert.Equal(4, clone.HorizontalResolution); + Assert.Equal(2, clone.VerticalResolution); + Assert.Equal(imageProperty, clone.Properties[0]); + Assert.Equal(24, clone.Quality); + Assert.Equal(1, clone.RepeatCount); + } + } +} From 9fbc44e14cfaf2eba0bfe7a1ff66d76712a239c1 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 5 Feb 2017 12:34:36 +0100 Subject: [PATCH 3/6] Fixed folder name. --- src/ImageSharp/{Metadata => MetaData}/IMetaData.cs | 0 src/ImageSharp/{Metadata => MetaData}/ImageFrameMetaData.cs | 0 src/ImageSharp/{Metadata => MetaData}/ImageMetaData.cs | 0 src/ImageSharp/{Metadata => MetaData}/ImageProperty.cs | 0 .../{Metadata => MetaData}/Profiles/Exif/ExifDataType.cs | 0 src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifParts.cs | 0 .../{Metadata => MetaData}/Profiles/Exif/ExifProfile.cs | 0 src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifReader.cs | 0 src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifTag.cs | 0 .../Profiles/Exif/ExifTagDescriptionAttribute.cs | 0 src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifValue.cs | 0 src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifWriter.cs | 0 src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/README.md | 0 .../{Metadata => MetaData}/ImageFrameMetaDataTests.cs | 0 .../ImageSharp.Tests/{Metadata => MetaData}/ImageMetaDataTests.cs | 0 .../ImageSharp.Tests/{Metadata => MetaData}/ImagePropertyTests.cs | 0 .../{Metadata => MetaData}/Profiles/Exif/ExifProfileTests.cs | 0 .../Profiles/Exif/ExifTagDescriptionAttributeTests.cs | 0 .../{Metadata => MetaData}/Profiles/Exif/ExifValueTests.cs | 0 19 files changed, 0 insertions(+), 0 deletions(-) rename src/ImageSharp/{Metadata => MetaData}/IMetaData.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/ImageFrameMetaData.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/ImageMetaData.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/ImageProperty.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifDataType.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifParts.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifProfile.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifReader.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifTag.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifTagDescriptionAttribute.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifValue.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/ExifWriter.cs (100%) rename src/ImageSharp/{Metadata => MetaData}/Profiles/Exif/README.md (100%) rename tests/ImageSharp.Tests/{Metadata => MetaData}/ImageFrameMetaDataTests.cs (100%) rename tests/ImageSharp.Tests/{Metadata => MetaData}/ImageMetaDataTests.cs (100%) rename tests/ImageSharp.Tests/{Metadata => MetaData}/ImagePropertyTests.cs (100%) rename tests/ImageSharp.Tests/{Metadata => MetaData}/Profiles/Exif/ExifProfileTests.cs (100%) rename tests/ImageSharp.Tests/{Metadata => MetaData}/Profiles/Exif/ExifTagDescriptionAttributeTests.cs (100%) rename tests/ImageSharp.Tests/{Metadata => MetaData}/Profiles/Exif/ExifValueTests.cs (100%) diff --git a/src/ImageSharp/Metadata/IMetaData.cs b/src/ImageSharp/MetaData/IMetaData.cs similarity index 100% rename from src/ImageSharp/Metadata/IMetaData.cs rename to src/ImageSharp/MetaData/IMetaData.cs diff --git a/src/ImageSharp/Metadata/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs similarity index 100% rename from src/ImageSharp/Metadata/ImageFrameMetaData.cs rename to src/ImageSharp/MetaData/ImageFrameMetaData.cs diff --git a/src/ImageSharp/Metadata/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs similarity index 100% rename from src/ImageSharp/Metadata/ImageMetaData.cs rename to src/ImageSharp/MetaData/ImageMetaData.cs diff --git a/src/ImageSharp/Metadata/ImageProperty.cs b/src/ImageSharp/MetaData/ImageProperty.cs similarity index 100% rename from src/ImageSharp/Metadata/ImageProperty.cs rename to src/ImageSharp/MetaData/ImageProperty.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifDataType.cs similarity index 100% rename from src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs rename to src/ImageSharp/MetaData/Profiles/Exif/ExifDataType.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifParts.cs similarity index 100% rename from src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs rename to src/ImageSharp/MetaData/Profiles/Exif/ExifParts.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs similarity index 100% rename from src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs rename to src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs similarity index 100% rename from src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs rename to src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifTag.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifTag.cs similarity index 100% rename from src/ImageSharp/Metadata/Profiles/Exif/ExifTag.cs rename to src/ImageSharp/MetaData/Profiles/Exif/ExifTag.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifTagDescriptionAttribute.cs similarity index 100% rename from src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs rename to src/ImageSharp/MetaData/Profiles/Exif/ExifTagDescriptionAttribute.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs similarity index 100% rename from src/ImageSharp/Metadata/Profiles/Exif/ExifValue.cs rename to src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs similarity index 100% rename from src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs rename to src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs diff --git a/src/ImageSharp/Metadata/Profiles/Exif/README.md b/src/ImageSharp/MetaData/Profiles/Exif/README.md similarity index 100% rename from src/ImageSharp/Metadata/Profiles/Exif/README.md rename to src/ImageSharp/MetaData/Profiles/Exif/README.md diff --git a/tests/ImageSharp.Tests/Metadata/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Metadata/ImageFrameMetaDataTests.cs rename to tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs diff --git a/tests/ImageSharp.Tests/Metadata/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Metadata/ImageMetaDataTests.cs rename to tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs diff --git a/tests/ImageSharp.Tests/Metadata/ImagePropertyTests.cs b/tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Metadata/ImagePropertyTests.cs rename to tests/ImageSharp.Tests/MetaData/ImagePropertyTests.cs diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs rename to tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifTagDescriptionAttributeTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs rename to tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifTagDescriptionAttributeTests.cs diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifValueTests.cs similarity index 100% rename from tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs rename to tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifValueTests.cs From 7024deccab987d53bddc2a78cfaa00869dc9f1a5 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 5 Feb 2017 13:14:35 +0100 Subject: [PATCH 4/6] Added method to update the profile data (based on #96) --- .../JpegEncoderCore.cs | 1 + src/ImageSharp/MetaData/ImageMetaData.cs | 29 ++++++++++++++++ .../MetaData/ImageMetaDataTests.cs | 33 +++++++++++++++++++ .../Profiles/Exif/ExifProfileTests.cs | 3 ++ 4 files changed, 66 insertions(+) diff --git a/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs b/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs index 9cc51c777..657470f5c 100644 --- a/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs @@ -706,6 +706,7 @@ namespace ImageSharp.Formats private void WriteProfiles(Image image) where TColor : struct, IPackedPixel, IEquatable { + image.MetaData.SyncProfiles(); this.WriteProfile(image.MetaData.ExifProfile); } diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index a38899840..0bd0d0f78 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -136,5 +136,34 @@ namespace ImageSharp /// 0 means to repeat indefinitely. /// public ushort RepeatCount { get; set; } + + /// + /// Synchronizes the profiles with the current meta data. + /// + internal void SyncProfiles() + { + this.SyncExifProfile(); + } + + private void SyncExifProfile() + { + if (this.ExifProfile == null) + { + return; + } + + this.SyncExifResolution(ExifTag.XResolution, this.HorizontalResolution); + this.SyncExifResolution(ExifTag.YResolution, this.VerticalResolution); + } + + private void SyncExifResolution(ExifTag tag, double resolution) + { + ExifValue value = this.ExifProfile.GetValue(tag); + if (value != null) + { + Rational newResolution = new Rational(resolution, false); + this.ExifProfile.SetValue(tag, newResolution); + } + } } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index 9034b88c0..d9bd52c73 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -38,5 +38,38 @@ namespace ImageSharp.Tests Assert.Equal(24, clone.Quality); Assert.Equal(1, clone.RepeatCount); } + + [Fact] + public void SyncProfiles() + { + ExifProfile exifProfile = new ExifProfile(); + exifProfile.SetValue(ExifTag.XResolution, new Rational(200)); + exifProfile.SetValue(ExifTag.YResolution, new Rational(300)); + + Image image = new Image(1, 1); + image.MetaData.ExifProfile = exifProfile; + image.MetaData.HorizontalResolution = 200; + image.MetaData.VerticalResolution = 300; + + image.MetaData.HorizontalResolution = 100; + + Assert.Equal(200, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(300, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + + image.MetaData.SyncProfiles(); + + Assert.Equal(100, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(300, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + + image.MetaData.VerticalResolution = 150; + + Assert.Equal(100, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(300, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + + image.MetaData.SyncProfiles(); + + Assert.Equal(100, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(150, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + } } } diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index 61307da20..f4a2bcf40 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -150,6 +150,9 @@ namespace ImageSharp.Tests image.MetaData.ExifProfile.SetValue(ExifTag.XResolution, new Rational(150.0)); + // We also need to change this value because this overrides XResolution when the image is written. + image.MetaData.HorizontalResolution = 150.0; + value = image.MetaData.ExifProfile.GetValue(ExifTag.XResolution); TestValue(value, new Rational(150, 1)); From 4d6cfcf8f5a842ed1b17d504ff4b4fc5f89d9195 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sun, 5 Feb 2017 14:54:43 +0100 Subject: [PATCH 5/6] Added unit test for Horizontal and Vertical resolution. --- src/ImageSharp/MetaData/ImageMetaData.cs | 4 +-- .../MetaData/ImageMetaDataTests.cs | 32 +++++++++++++++++++ 2 files changed, 34 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 0bd0d0f78..f4aef9863 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -79,7 +79,7 @@ namespace ImageSharp set { - if (value >= 0) + if (value > 0) { this.horizontalResolution = value; } @@ -100,7 +100,7 @@ namespace ImageSharp set { - if (value >= 0) + if (value > 0) { this.verticalResolution = value; } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index d9bd52c73..60e04e18d 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -39,6 +39,38 @@ namespace ImageSharp.Tests Assert.Equal(1, clone.RepeatCount); } + [Fact] + public void HorizontalResolution() + { + ImageMetaData metaData = new ImageMetaData(); + Assert.Equal(96, metaData.HorizontalResolution); + + metaData.HorizontalResolution=0; + Assert.Equal(96, metaData.HorizontalResolution); + + metaData.HorizontalResolution=-1; + Assert.Equal(96, metaData.HorizontalResolution); + + metaData.HorizontalResolution=1; + Assert.Equal(1, metaData.HorizontalResolution); + } + + [Fact] + public void VerticalResolution() + { + ImageMetaData metaData = new ImageMetaData(); + Assert.Equal(96, metaData.VerticalResolution); + + metaData.VerticalResolution = 0; + Assert.Equal(96, metaData.VerticalResolution); + + metaData.VerticalResolution = -1; + Assert.Equal(96, metaData.VerticalResolution); + + metaData.VerticalResolution = 1; + Assert.Equal(1, metaData.VerticalResolution); + } + [Fact] public void SyncProfiles() { From 6550d3f1cfe56a7dc781dbcf5c0385419722f746 Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Tue, 7 Feb 2017 07:43:02 +0100 Subject: [PATCH 6/6] Moved synchronization code to the ExifProfile. --- src/ImageSharp/MetaData/ImageMetaData.cs | 23 +------------ .../MetaData/Profiles/Exif/ExifProfile.cs | 20 +++++++++++ .../MetaData/ImageMetaDataTests.cs | 23 +++---------- .../Profiles/Exif/ExifProfileTests.cs | 33 +++++++++++++++++++ 4 files changed, 58 insertions(+), 41 deletions(-) diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index f4aef9863..a40df3110 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -142,28 +142,7 @@ namespace ImageSharp /// internal void SyncProfiles() { - this.SyncExifProfile(); - } - - private void SyncExifProfile() - { - if (this.ExifProfile == null) - { - return; - } - - this.SyncExifResolution(ExifTag.XResolution, this.HorizontalResolution); - this.SyncExifResolution(ExifTag.YResolution, this.VerticalResolution); - } - - private void SyncExifResolution(ExifTag tag, double resolution) - { - ExifValue value = this.ExifProfile.GetValue(tag); - if (value != null) - { - Rational newResolution = new Rational(resolution, false); - this.ExifProfile.SetValue(tag, newResolution); - } + this.ExifProfile?.Sync(this); } } } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 507463985..3bd5ef3cb 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -224,6 +224,26 @@ namespace ImageSharp return writer.GetData(); } + /// + /// Synchronizes the profiles with the specified meta data. + /// + /// The meta data. + internal void Sync(ImageMetaData metaData) + { + this.SyncResolution(ExifTag.XResolution, metaData.HorizontalResolution); + this.SyncResolution(ExifTag.YResolution, metaData.VerticalResolution); + } + + private void SyncResolution(ExifTag tag, double resolution) + { + ExifValue value = this.GetValue(tag); + if (value != null) + { + Rational newResolution = new Rational(resolution, false); + this.SetValue(tag, newResolution); + } + } + private void InitializeValues() { if (this.values != null) diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index 60e04e18d..3c0057b62 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -80,28 +80,13 @@ namespace ImageSharp.Tests Image image = new Image(1, 1); image.MetaData.ExifProfile = exifProfile; - image.MetaData.HorizontalResolution = 200; - image.MetaData.VerticalResolution = 300; - - image.MetaData.HorizontalResolution = 100; - - Assert.Equal(200, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); - Assert.Equal(300, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); - - image.MetaData.SyncProfiles(); - - Assert.Equal(100, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); - Assert.Equal(300, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); - - image.MetaData.VerticalResolution = 150; - - Assert.Equal(100, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); - Assert.Equal(300, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + image.MetaData.HorizontalResolution = 400; + image.MetaData.VerticalResolution = 500; image.MetaData.SyncProfiles(); - Assert.Equal(100, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); - Assert.Equal(150, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + Assert.Equal(400, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(500, ((Rational)image.MetaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); } } } diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index f4a2bcf40..8ec57057f 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -203,6 +203,39 @@ namespace ImageSharp.Tests Assert.Equal(7, image.MetaData.ExifProfile.Values.Count()); } + [Fact] + public void Syncs() + { + ExifProfile exifProfile = new ExifProfile(); + exifProfile.SetValue(ExifTag.XResolution, new Rational(200)); + exifProfile.SetValue(ExifTag.YResolution, new Rational(300)); + + ImageMetaData metaData = new ImageMetaData(); + metaData.ExifProfile = exifProfile; + metaData.HorizontalResolution = 200; + metaData.VerticalResolution = 300; + + metaData.HorizontalResolution = 100; + + Assert.Equal(200, ((Rational)metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(300, ((Rational)metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + + exifProfile.Sync(metaData); + + Assert.Equal(100, ((Rational)metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(300, ((Rational)metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + + metaData.VerticalResolution = 150; + + Assert.Equal(100, ((Rational)metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(300, ((Rational)metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + + exifProfile.Sync(metaData); + + Assert.Equal(100, ((Rational)metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble()); + Assert.Equal(150, ((Rational)metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble()); + } + [Fact] public void Values() {