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..e6f7b6136 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
{
@@ -321,12 +321,14 @@ namespace ImageSharp.Formats
if (this.previousFrame == null)
{
- 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);
+ 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 e5b8ba08a..80c9ee36b 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++)
@@ -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.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..657470f5c 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,8 @@ namespace ImageSharp.Formats
private void WriteProfiles(Image image)
where TColor : struct, IPackedPixel, IEquatable
{
- this.WriteProfile(image.ExifProfile);
+ image.MetaData.SyncProfiles();
+ 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..707fea235 100644
--- a/src/ImageSharp/Image/IImageBase.cs
+++ b/src/ImageSharp/Image/IImageBase.cs
@@ -15,19 +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
- /// 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.
///
@@ -52,5 +39,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/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 b179d1158..fd82f7730 100644
--- a/src/ImageSharp/Image/ImageBase{TColor}.cs
+++ b/src/ImageSharp/Image/ImageBase{TColor}.cs
@@ -110,12 +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; }
-
///
/// Gets the configuration providing initialization code which allows extending the library.
///
@@ -181,16 +175,16 @@ 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)
{
+ Debug.Assert(other != null);
+
this.Configuration = other.Configuration;
- this.Quality = other.Quality;
- this.FrameDelay = other.FrameDelay;
}
///
diff --git a/src/ImageSharp/Image/ImageFrame{TColor}.cs b/src/ImageSharp/Image/ImageFrame{TColor}.cs
index 809eca1a4..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()
{
@@ -55,11 +60,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())
@@ -90,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/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/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
new file mode 100644
index 000000000..a40df3110
--- /dev/null
+++ b/src/ImageSharp/MetaData/ImageMetaData.cs
@@ -0,0 +1,148 @@
+//
+// 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 : IMetaData
+ {
+ ///
+ /// 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;
+ this.FrameDelay = other.FrameDelay;
+ this.RepeatCount = other.RepeatCount;
+
+ 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 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.
+ ///
+ /// 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; }
+
+ ///
+ /// Synchronizes the profiles with the current meta data.
+ ///
+ internal void SyncProfiles()
+ {
+ this.ExifProfile?.Sync(this);
+ }
+ }
+}
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 91%
rename from src/ImageSharp/Profiles/Exif/ExifProfile.cs
rename to src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs
index 507463985..3bd5ef3cb 100644
--- a/src/ImageSharp/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/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/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..3c0057b62
--- /dev/null
+++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs
@@ -0,0 +1,92 @@
+//
+// 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);
+ }
+
+ [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()
+ {
+ 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 = 400;
+ image.MetaData.VerticalResolution = 500;
+
+ image.MetaData.SyncProfiles();
+
+ 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/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 59%
rename from tests/ImageSharp.Tests/Profiles/Exif/ExifProfileTests.cs
rename to tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs
index 1900b58c6..8ec57057f 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,107 @@ 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);
+ // 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));
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.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.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());
- 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));
+ exifProfile.Sync(metaData);
- Assert.Equal(7, image.ExifProfile.Values.Count());
+ Assert.Equal(100, ((Rational)metaData.ExifProfile.GetValue(ExifTag.XResolution).Value).ToDouble());
+ Assert.Equal(150, ((Rational)metaData.ExifProfile.GetValue(ExifTag.YResolution).Value).ToDouble());
}
[Fact]
@@ -225,8 +259,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 +272,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}"))