Browse Source

Moved the meta data of the image to a new MetaData property.

af/merge-core
Dirk Lemstra 9 years ago
parent
commit
7ea3238d83
  1. 1
      ImageSharp.ruleset
  2. 4
      src/ImageSharp.Formats.Gif/GifDecoderCore.cs
  3. 4
      src/ImageSharp.Formats.Gif/GifEncoderCore.cs
  4. 6
      src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs
  5. 4
      src/ImageSharp.Formats.Jpeg/JpegEncoder.cs
  6. 4
      src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs
  7. 8
      src/ImageSharp.Formats.Png/PngDecoderCore.cs
  8. 12
      src/ImageSharp.Formats.Png/PngEncoderCore.cs
  9. 6
      src/ImageSharp.Processing/Transforms/AutoOrient.cs
  10. 25
      src/ImageSharp/Image/IImage.cs
  11. 10
      src/ImageSharp/Image/IImageBase.cs
  12. 14
      src/ImageSharp/Image/ImageBase{TColor}.cs
  13. 7
      src/ImageSharp/Image/ImageFrame{TColor}.cs
  14. 113
      src/ImageSharp/Image/Image{TColor}.cs
  15. 130
      src/ImageSharp/Metadata/ImageMetaData.cs
  16. 16
      src/ImageSharp/Metadata/ImageProperty.cs
  17. 0
      src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs
  18. 0
      src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs
  19. 0
      src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs
  20. 0
      src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs
  21. 0
      src/ImageSharp/Metadata/Profiles/Exif/ExifTag.cs
  22. 0
      src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs
  23. 0
      src/ImageSharp/Metadata/Profiles/Exif/ExifValue.cs
  24. 0
      src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs
  25. 0
      src/ImageSharp/Metadata/Profiles/Exif/README.md
  26. 4
      tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs
  27. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
  28. 2
      tests/ImageSharp.Tests/Formats/Png/PngTests.cs
  29. 0
      tests/ImageSharp.Tests/Metadata/ImagePropertyTests.cs
  30. 90
      tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs
  31. 0
      tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs
  32. 2
      tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs
  33. 4
      tests/ImageSharp.Tests/Processors/Filters/AutoOrientTests.cs

1
ImageSharp.ruleset

@ -1,6 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="ImageSharp" ToolsVersion="14.0"> <RuleSet Name="ImageSharp" ToolsVersion="14.0">
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers"> <Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1405" Action="None" />
<Rule Id="SA1413" Action="None" /> <Rule Id="SA1413" Action="None" />
</Rules> </Rules>
</RuleSet> </RuleSet>

4
src/ImageSharp.Formats.Gif/GifDecoderCore.cs

@ -239,7 +239,7 @@ namespace ImageSharp.Formats
try try
{ {
this.currentStream.Read(flagBuffer, 0, flag); 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 finally
{ {
@ -323,7 +323,7 @@ namespace ImageSharp.Formats
{ {
image = this.decodedImage; 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. // This initializes the image to become fully transparent because the alpha channel is zero.
image.InitPixels(imageWidth, imageHeight); image.InitPixels(imageWidth, imageHeight);

4
src/ImageSharp.Formats.Gif/GifEncoderCore.cs

@ -65,7 +65,7 @@ namespace ImageSharp.Formats
EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream); EndianBinaryWriter writer = new EndianBinaryWriter(Endianness.LittleEndian, stream);
// Ensure that quality can be set but has a fallback. // 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; this.Quality = quality > 0 ? quality.Clamp(1, 256) : 256;
// Get the number of bits. // Get the number of bits.
@ -91,7 +91,7 @@ namespace ImageSharp.Formats
// Write additional frames. // Write additional frames.
if (image.Frames.Any()) 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 // ReSharper disable once ForCanBeConvertedToForeach
for (int i = 0; i < image.Frames.Count; i++) for (int i = 0; i < image.Frames.Count; i++)

6
src/ImageSharp.Formats.Jpeg/JpegDecoderCore.cs

@ -547,8 +547,8 @@ namespace ImageSharp.Formats
{ {
if (this.isJfif && this.horizontalResolution > 0 && this.verticalResolution > 0) if (this.isJfif && this.horizontalResolution > 0 && this.verticalResolution > 0)
{ {
image.HorizontalResolution = this.horizontalResolution; image.MetaData.HorizontalResolution = this.horizontalResolution;
image.VerticalResolution = this.verticalResolution; 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' if (profile[0] == 'E' && profile[1] == 'x' && profile[2] == 'i' && profile[3] == 'f' && profile[4] == '\0'
&& profile[5] == '\0') && profile[5] == '\0')
{ {
image.ExifProfile = new ExifProfile(profile); image.MetaData.ExifProfile = new ExifProfile(profile);
} }
} }

4
src/ImageSharp.Formats.Jpeg/JpegEncoder.cs

@ -65,9 +65,9 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
// Ensure that quality can be set but has a fallback. // 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(); JpegEncoderCore encode = new JpegEncoderCore();

4
src/ImageSharp.Formats.Jpeg/JpegEncoderCore.cs

@ -200,7 +200,7 @@ namespace ImageSharp.Formats
int componentCount = 3; int componentCount = 3;
// Write the Start Of Image marker. // 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); this.WriteProfiles(image);
@ -706,7 +706,7 @@ namespace ImageSharp.Formats
private void WriteProfiles<TColor>(Image<TColor> image) private void WriteProfiles<TColor>(Image<TColor> image)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
this.WriteProfile(image.ExifProfile); this.WriteProfile(image.MetaData.ExifProfile);
} }
/// <summary> /// <summary>

8
src/ImageSharp.Formats.Png/PngDecoderCore.cs

@ -174,7 +174,7 @@ namespace ImageSharp.Formats
byte[] pal = new byte[currentChunk.Length]; byte[] pal = new byte[currentChunk.Length];
Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length); Buffer.BlockCopy(currentChunk.Data, 0, pal, 0, currentChunk.Length);
this.palette = pal; this.palette = pal;
image.Quality = pal.Length / 3; image.MetaData.Quality = pal.Length / 3;
break; break;
case PngChunkTypes.PaletteAlpha: case PngChunkTypes.PaletteAlpha:
byte[] alpha = new byte[currentChunk.Length]; byte[] alpha = new byte[currentChunk.Length];
@ -268,8 +268,8 @@ namespace ImageSharp.Formats
data.ReverseBytes(4, 4); data.ReverseBytes(4, 4);
// 39.3700787 = inches in a meter. // 39.3700787 = inches in a meter.
image.HorizontalResolution = BitConverter.ToInt32(data, 0) / 39.3700787d; image.MetaData.HorizontalResolution = BitConverter.ToInt32(data, 0) / 39.3700787d;
image.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d; image.MetaData.VerticalResolution = BitConverter.ToInt32(data, 4) / 39.3700787d;
} }
/// <summary> /// <summary>
@ -777,7 +777,7 @@ namespace ImageSharp.Formats
string name = Encoding.Unicode.GetString(data, 0, zeroIndex); string name = Encoding.Unicode.GetString(data, 0, zeroIndex);
string value = Encoding.Unicode.GetString(data, zeroIndex + 1, length - zeroIndex - 1); 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));
} }
/// <summary> /// <summary>

12
src/ImageSharp.Formats.Png/PngEncoderCore.cs

@ -126,12 +126,12 @@ namespace ImageSharp.Formats
public byte Threshold { get; set; } public byte Threshold { get; set; }
/// <summary> /// <summary>
/// Encodes the image to the specified stream from the <see cref="ImageBase{TColor}"/>. /// Encodes the image to the specified stream from the <see cref="Image{TColor}"/>.
/// </summary> /// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TColor">The pixel format.</typeparam>
/// <param name="image">The <see cref="ImageBase{TColor}"/> to encode from.</param> /// <param name="image">The <see cref="ImageBase{TColor}"/> to encode from.</param>
/// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param> /// <param name="stream">The <see cref="Stream"/> to encode the image data to.</param>
public void Encode<TColor>(ImageBase<TColor> image, Stream stream) public void Encode<TColor>(Image<TColor> image, Stream stream)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
Guard.NotNull(image, nameof(image)); Guard.NotNull(image, nameof(image));
@ -153,7 +153,7 @@ namespace ImageSharp.Formats
stream.Write(this.chunkDataBuffer, 0, 8); stream.Write(this.chunkDataBuffer, 0, 8);
// Ensure that quality can be set but has a fallback. // 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; this.Quality = quality > 0 ? quality.Clamp(1, int.MaxValue) : int.MaxValue;
// Set correct color type if the color count is 256 or less. // Set correct color type if the color count is 256 or less.
@ -557,11 +557,11 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
Image<TColor> image = imageBase as Image<TColor>; Image<TColor> image = imageBase as Image<TColor>;
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. // 39.3700787 = inches in a meter.
int dpmX = (int)Math.Round(image.HorizontalResolution * 39.3700787D); int dpmX = (int)Math.Round(image.MetaData.HorizontalResolution * 39.3700787D);
int dpmY = (int)Math.Round(image.VerticalResolution * 39.3700787D); int dpmY = (int)Math.Round(image.MetaData.VerticalResolution * 39.3700787D);
WriteInteger(this.chunkDataBuffer, 0, dpmX); WriteInteger(this.chunkDataBuffer, 0, dpmX);
WriteInteger(this.chunkDataBuffer, 4, dpmY); WriteInteger(this.chunkDataBuffer, 4, dpmY);

6
src/ImageSharp.Processing/Transforms/AutoOrient.cs

@ -66,12 +66,12 @@ namespace ImageSharp
private static Orientation GetExifOrientation<TColor>(Image<TColor> source) private static Orientation GetExifOrientation<TColor>(Image<TColor> source)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
if (source.ExifProfile == null) if (source.MetaData.ExifProfile == null)
{ {
return Orientation.Unknown; return Orientation.Unknown;
} }
ExifValue value = source.ExifProfile.GetValue(ExifTag.Orientation); ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation);
if (value == null) if (value == null)
{ {
return Orientation.Unknown; return Orientation.Unknown;
@ -79,7 +79,7 @@ namespace ImageSharp
Orientation orientation = (Orientation)value.Value; Orientation orientation = (Orientation)value.Value;
source.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft); source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft);
return orientation; return orientation;
} }

25
src/ImageSharp/Image/IImage.cs

@ -0,0 +1,25 @@
// <copyright file="IImage.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using Formats;
/// <summary>
/// Encapsulates the basic properties and methods required to manipulate images.
/// </summary>
internal interface IImage : IImageBase
{
/// <summary>
/// Gets the currently loaded image format.
/// </summary>
IImageFormat CurrentImageFormat { get; }
/// <summary>
/// Gets the meta data of the image.
/// </summary>
ImageMetaData MetaData { get; }
}
}

10
src/ImageSharp/Image/IImageBase.cs

@ -15,11 +15,6 @@ namespace ImageSharp
/// </summary> /// </summary>
Rectangle Bounds { get; } Rectangle Bounds { get; }
/// <summary>
/// Gets or sets the quality of the image. This affects the output quality of lossy image formats.
/// </summary>
int Quality { get; set; }
/// <summary> /// <summary>
/// Gets or sets the frame delay for animated images. /// 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 /// 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. /// Gets the pixel ratio made up of the width and height.
/// </summary> /// </summary>
double PixelRatio { get; } double PixelRatio { get; }
/// <summary>
/// Gets the configuration providing initialization code which allows extending the library.
/// </summary>
Configuration Configuration { get; }
} }
} }

14
src/ImageSharp/Image/ImageBase{TColor}.cs

@ -110,9 +110,6 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height); public Rectangle Bounds => new Rectangle(0, 0, this.Width, this.Height);
/// <inheritdoc/>
public int Quality { get; set; }
/// <inheritdoc/> /// <inheritdoc/>
public int FrameDelay { get; set; } public int FrameDelay { get; set; }
@ -181,16 +178,17 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Copies the properties from the other <see cref="ImageBase{TColor}"/>. /// Copies the properties from the other <see cref="IImageBase"/>.
/// </summary> /// </summary>
/// <param name="other"> /// <param name="other">
/// The other <see cref="ImageBase{TColor}"/> to copy the properties from. /// The other <see cref="IImageBase"/> to copy the properties from.
/// </param> /// </param>
protected void CopyProperties(ImageBase<TColor> other) protected void CopyProperties(IImageBase other)
{ {
this.Configuration = other.Configuration; Debug.Assert(other != null);
this.Quality = other.Quality;
this.FrameDelay = other.FrameDelay; this.FrameDelay = other.FrameDelay;
this.Configuration = other.Configuration;
} }
/// <summary> /// <summary>

7
src/ImageSharp/Image/ImageFrame{TColor}.cs

@ -55,11 +55,8 @@ namespace ImageSharp
{ {
scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TColor, TColor2>(scaleFunc); scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TColor, TColor2>(scaleFunc);
ImageFrame<TColor2> target = new ImageFrame<TColor2>(this.Width, this.Height, this.Configuration) ImageFrame<TColor2> target = new ImageFrame<TColor2>(this.Width, this.Height, this.Configuration);
{ target.CopyProperties(this);
Quality = this.Quality,
FrameDelay = this.FrameDelay
};
using (PixelAccessor<TColor> pixels = this.Lock()) using (PixelAccessor<TColor> pixels = this.Lock())
using (PixelAccessor<TColor2> targetPixels = target.Lock()) using (PixelAccessor<TColor2> targetPixels = target.Lock())

113
src/ImageSharp/Image/Image{TColor}.cs

@ -23,21 +23,9 @@ namespace ImageSharp
/// </summary> /// </summary>
/// <typeparam name="TColor">The pixel format.</typeparam> /// <typeparam name="TColor">The pixel format.</typeparam>
[DebuggerDisplay("Image: {Width}x{Height}")] [DebuggerDisplay("Image: {Width}x{Height}")]
public class Image<TColor> : ImageBase<TColor> public class Image<TColor> : ImageBase<TColor>, IImage
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
/// <summary>
/// The default horizontal resolution value (dots per inch) in x direction.
/// <remarks>The default value is 96 dots per inch.</remarks>
/// </summary>
public const double DefaultHorizontalResolution = 96;
/// <summary>
/// The default vertical resolution value (dots per inch) in y direction.
/// <remarks>The default value is 96 dots per inch.</remarks>
/// </summary>
public const double DefaultVerticalResolution = 96;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Image{TColor}"/> class /// Initializes a new instance of the <see cref="Image{TColor}"/> class
/// with the height and the width of the image. /// with the height and the width of the image.
@ -129,18 +117,9 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Gets or sets the resolution of the image in x- direction. It is defined as /// Gets the meta data of the image.
/// number of dots per inch and should be an positive value.
/// </summary>
/// <value>The density of the image in x- direction.</value>
public double HorizontalResolution { get; set; } = DefaultHorizontalResolution;
/// <summary>
/// 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.
/// </summary> /// </summary>
/// <value>The density of the image in y- direction.</value> public ImageMetaData MetaData { get; private set; } = new ImageMetaData();
public double VerticalResolution { get; set; } = DefaultVerticalResolution;
/// <summary> /// <summary>
/// Gets the width of the image in inches. It is calculated as the width of the image /// Gets the width of the image in inches. It is calculated as the width of the image
@ -152,14 +131,7 @@ namespace ImageSharp
{ {
get get
{ {
double resolution = this.HorizontalResolution; return this.Width / this.MetaData.HorizontalResolution;
if (resolution <= 0)
{
resolution = DefaultHorizontalResolution;
}
return this.Width / resolution;
} }
} }
@ -173,14 +145,7 @@ namespace ImageSharp
{ {
get get
{ {
double resolution = this.VerticalResolution; return this.Height / this.MetaData.VerticalResolution;
if (resolution <= 0)
{
resolution = DefaultVerticalResolution;
}
return this.Height / resolution;
} }
} }
@ -192,34 +157,17 @@ namespace ImageSharp
/// </value> /// </value>
public bool IsAnimated => this.Frames.Count > 0; public bool IsAnimated => this.Frames.Count > 0;
/// <summary>
/// Gets or sets the number of times any animation is repeated.
/// <remarks>0 means to repeat indefinitely.</remarks>
/// </summary>
public ushort RepeatCount { get; set; }
/// <summary> /// <summary>
/// Gets the other frames for the animation. /// Gets the other frames for the animation.
/// </summary> /// </summary>
/// <value>The list of frame images.</value> /// <value>The list of frame images.</value>
public IList<ImageFrame<TColor>> Frames { get; } = new List<ImageFrame<TColor>>(); public IList<ImageFrame<TColor>> Frames { get; } = new List<ImageFrame<TColor>>();
/// <summary>
/// Gets the list of properties for storing meta information about this image.
/// </summary>
/// <value>A list of image properties.</value>
public IList<ImageProperty> Properties { get; } = new List<ImageProperty>();
/// <summary> /// <summary>
/// Gets the currently loaded image format. /// Gets the currently loaded image format.
/// </summary> /// </summary>
public IImageFormat CurrentImageFormat { get; internal set; } public IImageFormat CurrentImageFormat { get; internal set; }
/// <summary>
/// Gets or sets the Exif profile.
/// </summary>
public ExifProfile ExifProfile { get; set; }
/// <summary> /// <summary>
/// Applies the processor to the image. /// Applies the processor to the image.
/// </summary> /// </summary>
@ -317,15 +265,8 @@ namespace ImageSharp
{ {
scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TColor, TColor2>(scaleFunc); scaleFunc = PackedPixelConverterHelper.ComputeScaleFunction<TColor, TColor2>(scaleFunc);
Image<TColor2> target = new Image<TColor2>(this.Width, this.Height, this.Configuration) Image<TColor2> target = new Image<TColor2>(this.Width, this.Height, this.Configuration);
{ target.CopyProperties(this);
Quality = this.Quality,
FrameDelay = this.FrameDelay,
HorizontalResolution = this.HorizontalResolution,
VerticalResolution = this.VerticalResolution,
CurrentImageFormat = this.CurrentImageFormat,
RepeatCount = this.RepeatCount
};
using (PixelAccessor<TColor> pixels = this.Lock()) using (PixelAccessor<TColor> pixels = this.Lock())
using (PixelAccessor<TColor2> targetPixels = target.Lock()) using (PixelAccessor<TColor2> 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++) for (int i = 0; i < this.Frames.Count; i++)
{ {
target.Frames.Add(this.Frames[i].To<TColor2>()); target.Frames.Add(this.Frames[i].To<TColor2>());
@ -358,27 +294,6 @@ namespace ImageSharp
return target; return target;
} }
/// <summary>
/// Copies the properties from the other <see cref="Image{TColor}"/>.
/// </summary>
/// <param name="other">
/// The other <see cref="Image{TColor}"/> to copy the properties from.
/// </param>
internal void CopyProperties(Image<TColor> 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);
}
}
/// <summary> /// <summary>
/// Creates a new <see cref="ImageFrame{TColor}"/> from this instance /// Creates a new <see cref="ImageFrame{TColor}"/> from this instance
/// </summary> /// </summary>
@ -400,6 +315,20 @@ namespace ImageSharp
base.Dispose(disposing); base.Dispose(disposing);
} }
/// <summary>
/// Copies the properties from the other <see cref="IImage"/>.
/// </summary>
/// <param name="other">
/// The other <see cref="IImage"/> to copy the properties from.
/// </param>
private void CopyProperties(IImage other)
{
base.CopyProperties(other);
this.CurrentImageFormat = other.CurrentImageFormat;
this.MetaData = new ImageMetaData(other.MetaData);
}
/// <summary> /// <summary>
/// Loads the image from the given stream. /// Loads the image from the given stream.
/// </summary> /// </summary>

130
src/ImageSharp/Metadata/ImageMetaData.cs

@ -0,0 +1,130 @@
// <copyright file="ImageMetaData.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
using System.Collections.Generic;
using System.Diagnostics;
/// <summary>
/// Encapsulates the metadata of an image.
/// </summary>
public sealed class ImageMetaData
{
/// <summary>
/// The default horizontal resolution value (dots per inch) in x direction.
/// <remarks>The default value is 96 dots per inch.</remarks>
/// </summary>
public const double DefaultHorizontalResolution = 96;
/// <summary>
/// The default vertical resolution value (dots per inch) in y direction.
/// <remarks>The default value is 96 dots per inch.</remarks>
/// </summary>
public const double DefaultVerticalResolution = 96;
private double horizontalResolution;
private double verticalResolution;
/// <summary>
/// Initializes a new instance of the <see cref="ImageMetaData"/> class.
/// </summary>
internal ImageMetaData()
{
this.horizontalResolution = DefaultHorizontalResolution;
this.verticalResolution = DefaultVerticalResolution;
}
/// <summary>
/// Initializes a new instance of the <see cref="ImageMetaData"/> class
/// by making a copy from other metadata.
/// </summary>
/// <param name="other">
/// The other <see cref="ImageMetaData"/> to create this instance from.
/// </param>
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);
}
}
/// <summary>
/// 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.
/// </summary>
/// <value>The density of the image in x- direction.</value>
public double HorizontalResolution
{
get
{
return this.horizontalResolution;
}
set
{
if (value >= 0)
{
this.horizontalResolution = value;
}
}
}
/// <summary>
/// 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.
/// </summary>
/// <value>The density of the image in y- direction.</value>
public double VerticalResolution
{
get
{
return this.verticalResolution;
}
set
{
if (value >= 0)
{
this.verticalResolution = value;
}
}
}
/// <summary>
/// Gets or sets the Exif profile.
/// </summary>
public ExifProfile ExifProfile { get; set; }
/// <summary>
/// Gets the list of properties for storing meta information about this image.
/// </summary>
/// <value>A list of image properties.</value>
public IList<ImageProperty> Properties { get; } = new List<ImageProperty>();
/// <summary>
/// Gets or sets the quality of the image. This affects the output quality of lossy image formats.
/// </summary>
public int Quality { get; set; }
/// <summary>
/// Gets or sets the number of times any animation is repeated.
/// <remarks>0 means to repeat indefinitely.</remarks>
/// </summary>
public ushort RepeatCount { get; set; }
}
}

16
src/ImageSharp/Image/ImageProperty.cs → src/ImageSharp/Metadata/ImageProperty.cs

@ -6,6 +6,7 @@
namespace ImageSharp namespace ImageSharp
{ {
using System; using System;
using System.Diagnostics;
/// <summary> /// <summary>
/// Stores meta information about a image, like the name of the author, /// Stores meta information about a image, like the name of the author,
@ -27,6 +28,21 @@ namespace ImageSharp
this.Value = value; this.Value = value;
} }
/// <summary>
/// Initializes a new instance of the <see cref="ImageProperty"/> class
/// by making a copy from another property.
/// </summary>
/// <param name="other">
/// The other <see cref="ImageProperty"/> to create this instance from.
/// </param>
internal ImageProperty(ImageProperty other)
{
Debug.Assert(other != null);
this.Name = other.Name;
this.Value = other.Value;
}
/// <summary> /// <summary>
/// Gets the name of this <see cref="ImageProperty"/> indicating which kind of /// Gets the name of this <see cref="ImageProperty"/> indicating which kind of
/// information this property stores. /// information this property stores.

0
src/ImageSharp/Profiles/Exif/ExifDataType.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifDataType.cs

0
src/ImageSharp/Profiles/Exif/ExifParts.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifParts.cs

0
src/ImageSharp/Profiles/Exif/ExifProfile.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifProfile.cs

0
src/ImageSharp/Profiles/Exif/ExifReader.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs

0
src/ImageSharp/Profiles/Exif/ExifTag.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifTag.cs

0
src/ImageSharp/Profiles/Exif/ExifTagDescriptionAttribute.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifTagDescriptionAttribute.cs

0
src/ImageSharp/Profiles/Exif/ExifValue.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifValue.cs

0
src/ImageSharp/Profiles/Exif/ExifWriter.cs → src/ImageSharp/Metadata/Profiles/Exif/ExifWriter.cs

0
src/ImageSharp/Profiles/Exif/README.md → src/ImageSharp/Metadata/Profiles/Exif/README.md

4
tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs

@ -24,8 +24,8 @@ namespace ImageSharp.Tests
{ {
using (FileStream output = File.OpenWrite($"{path}/{file.FileName}")) using (FileStream output = File.OpenWrite($"{path}/{file.FileName}"))
{ {
image.VerticalResolution = 150; image.MetaData.VerticalResolution = 150;
image.HorizontalResolution = 150; image.MetaData.HorizontalResolution = 150;
image.Save(output); image.Save(output);
} }
} }

4
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

@ -36,8 +36,8 @@ namespace ImageSharp.Tests
{ {
using (Image<TColor> image = provider.GetImage().Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max })) using (Image<TColor> image = provider.GetImage().Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max }))
{ {
image.Quality = quality; image.MetaData.Quality = quality;
image.ExifProfile = null; // Reduce the size of the file image.MetaData.ExifProfile = null; // Reduce the size of the file
JpegEncoder encoder = new JpegEncoder { Subsample = subsample, Quality = quality }; JpegEncoder encoder = new JpegEncoder { Subsample = subsample, Quality = quality };
provider.Utility.TestName += $"{subsample}_Q{quality}"; provider.Utility.TestName += $"{subsample}_Q{quality}";

2
tests/ImageSharp.Tests/Formats/Png/PngTests.cs

@ -27,7 +27,7 @@ namespace ImageSharp.Tests
{ {
using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png")) using (FileStream output = File.OpenWrite($"{path}/{file.FileNameWithoutExtension}.png"))
{ {
image.Quality = 256; image.MetaData.Quality = 256;
image.Save(output, new PngFormat()); image.Save(output, new PngFormat());
} }
} }

0
tests/ImageSharp.Tests/Image/ImagePropertyTests.cs → tests/ImageSharp.Tests/Metadata/ImagePropertyTests.cs

90
tests/ImageSharp.Tests/Profiles/Exif/ExifProfileTests.cs → tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs

@ -19,20 +19,18 @@ namespace ImageSharp.Tests
{ {
Image image = TestFile.Create(TestImages.Jpeg.Baseline.Calliphora).CreateImage(); Image image = TestFile.Create(TestImages.Jpeg.Baseline.Calliphora).CreateImage();
Assert.Null(image.ExifProfile); Assert.Null(image.MetaData.ExifProfile);
image.ExifProfile = new ExifProfile(); image.MetaData.ExifProfile = new ExifProfile();
image.ExifProfile.SetValue(ExifTag.Copyright, "Dirk Lemstra"); image.MetaData.ExifProfile.SetValue(ExifTag.Copyright, "Dirk Lemstra");
image = WriteAndRead(image); image = WriteAndRead(image);
Assert.NotNull(image.ExifProfile); Assert.NotNull(image.MetaData.ExifProfile);
Assert.Equal(1, image.ExifProfile.Values.Count()); 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"); TestValue(value, "Dirk Lemstra");
} }
[Fact] [Fact]
@ -70,14 +68,14 @@ namespace ImageSharp.Tests
profile.SetValue(ExifTag.ExposureTime, new Rational(exposureTime)); profile.SetValue(ExifTag.ExposureTime, new Rational(exposureTime));
Image image = new Image(1, 1); Image image = new Image(1, 1);
image.ExifProfile = profile; image.MetaData.ExifProfile = profile;
image.SaveAsJpeg(memStream); image.SaveAsJpeg(memStream);
memStream.Position = 0; memStream.Position = 0;
image = new Image(memStream); image = new Image(memStream);
profile = image.ExifProfile; profile = image.MetaData.ExifProfile;
Assert.NotNull(profile); Assert.NotNull(profile);
ExifValue value = profile.GetValue(ExifTag.ExposureTime); ExifValue value = profile.GetValue(ExifTag.ExposureTime);
@ -88,14 +86,14 @@ namespace ImageSharp.Tests
profile = GetExifProfile(); profile = GetExifProfile();
profile.SetValue(ExifTag.ExposureTime, new Rational(exposureTime, true)); profile.SetValue(ExifTag.ExposureTime, new Rational(exposureTime, true));
image.ExifProfile = profile; image.MetaData.ExifProfile = profile;
image.SaveAsJpeg(memStream); image.SaveAsJpeg(memStream);
memStream.Position = 0; memStream.Position = 0;
image = new Image(memStream); image = new Image(memStream);
profile = image.ExifProfile; profile = image.MetaData.ExifProfile;
Assert.NotNull(profile); Assert.NotNull(profile);
value = profile.GetValue(ExifTag.ExposureTime); value = profile.GetValue(ExifTag.ExposureTime);
@ -107,24 +105,24 @@ namespace ImageSharp.Tests
public void ReadWriteInfinity() public void ReadWriteInfinity()
{ {
Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage(); 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); image = WriteAndRead(image);
ExifValue value = image.ExifProfile.GetValue(ExifTag.ExposureBiasValue); ExifValue value = image.MetaData.ExifProfile.GetValue(ExifTag.ExposureBiasValue);
Assert.NotNull(value); Assert.NotNull(value);
Assert.Equal(new SignedRational(double.PositiveInfinity), value.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); image = WriteAndRead(image);
value = image.ExifProfile.GetValue(ExifTag.ExposureBiasValue); value = image.MetaData.ExifProfile.GetValue(ExifTag.ExposureBiasValue);
Assert.NotNull(value); Assert.NotNull(value);
Assert.Equal(new SignedRational(double.NegativeInfinity), value.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); image = WriteAndRead(image);
value = image.ExifProfile.GetValue(ExifTag.FlashEnergy); value = image.MetaData.ExifProfile.GetValue(ExifTag.FlashEnergy);
Assert.NotNull(value); Assert.NotNull(value);
Assert.Equal(new Rational(double.PositiveInfinity), value.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) }; 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 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"); TestValue(value, "ImageSharp");
Assert.Throws<ArgumentException>(() => { value.Value = 15; }); Assert.Throws<ArgumentException>(() => { 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)); TestValue(value, new SignedRational(7555, 100));
Assert.Throws<ArgumentException>(() => { value.Value = 75; }); Assert.Throws<ArgumentException>(() => { 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)); TestValue(value, new Rational(150, 1));
Assert.Throws<ArgumentException>(() => { value.Value = "ImageSharp"; }); Assert.Throws<ArgumentException>(() => { 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); 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); TestValue(value, latitude);
image = WriteAndRead(image); image = WriteAndRead(image);
Assert.NotNull(image.ExifProfile); Assert.NotNull(image.MetaData.ExifProfile);
Assert.Equal(17, image.ExifProfile.Values.Count()); Assert.Equal(17, image.MetaData.ExifProfile.Values.Count());
value = image.ExifProfile.GetValue(ExifTag.Software); value = image.MetaData.ExifProfile.GetValue(ExifTag.Software);
TestValue(value, "ImageSharp"); TestValue(value, "ImageSharp");
value = image.ExifProfile.GetValue(ExifTag.ShutterSpeedValue); value = image.MetaData.ExifProfile.GetValue(ExifTag.ShutterSpeedValue);
TestValue(value, new SignedRational(75.55)); 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)); TestValue(value, new Rational(150.0));
value = image.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite); value = image.MetaData.ExifProfile.GetValue(ExifTag.ReferenceBlackWhite);
Assert.Null(value); Assert.Null(value);
value = image.ExifProfile.GetValue(ExifTag.GPSLatitude); value = image.MetaData.ExifProfile.GetValue(ExifTag.GPSLatitude);
TestValue(value, latitude); TestValue(value, latitude);
image.ExifProfile.Parts = ExifParts.ExifTags; image.MetaData.ExifProfile.Parts = ExifParts.ExifTags;
image = WriteAndRead(image); image = WriteAndRead(image);
Assert.NotNull(image.ExifProfile); Assert.NotNull(image.MetaData.ExifProfile);
Assert.Equal(8, image.ExifProfile.Values.Count()); Assert.Equal(8, image.MetaData.ExifProfile.Values.Count());
Assert.NotNull(image.ExifProfile.GetValue(ExifTag.ColorSpace)); Assert.NotNull(image.MetaData.ExifProfile.GetValue(ExifTag.ColorSpace));
Assert.True(image.ExifProfile.RemoveValue(ExifTag.ColorSpace)); Assert.True(image.MetaData.ExifProfile.RemoveValue(ExifTag.ColorSpace));
Assert.False(image.ExifProfile.RemoveValue(ExifTag.ColorSpace)); Assert.False(image.MetaData.ExifProfile.RemoveValue(ExifTag.ColorSpace));
Assert.Null(image.ExifProfile.GetValue(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] [Fact]
@ -225,8 +223,8 @@ namespace ImageSharp.Tests
} }
Image image = new Image(100, 100); Image image = new Image(100, 100);
image.ExifProfile = new ExifProfile(); image.MetaData.ExifProfile = new ExifProfile();
image.ExifProfile.SetValue(ExifTag.ImageDescription, junk.ToString()); image.MetaData.ExifProfile.SetValue(ExifTag.ImageDescription, junk.ToString());
using (MemoryStream memStream = new MemoryStream()) using (MemoryStream memStream = new MemoryStream())
{ {
@ -238,7 +236,7 @@ namespace ImageSharp.Tests
{ {
Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage(); Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage();
ExifProfile profile = image.ExifProfile; ExifProfile profile = image.MetaData.ExifProfile;
Assert.NotNull(profile); Assert.NotNull(profile);
return profile; return profile;

0
tests/ImageSharp.Tests/Profiles/Exif/ExifTagDescriptionAttributeTests.cs → tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifTagDescriptionAttributeTests.cs

2
tests/ImageSharp.Tests/Profiles/Exif/ExifValueTests.cs → tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifValueTests.cs

@ -15,7 +15,7 @@ namespace ImageSharp.Tests
ExifProfile profile; ExifProfile profile;
using (Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage()) using (Image image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage())
{ {
profile = image.ExifProfile; profile = image.MetaData.ExifProfile;
} }
Assert.NotNull(profile); Assert.NotNull(profile);

4
tests/ImageSharp.Tests/Processors/Filters/AutoOrientTests.cs

@ -35,8 +35,8 @@ namespace ImageSharp.Tests
using (Image image = file.CreateImage()) using (Image image = file.CreateImage())
{ {
image.ExifProfile = new ExifProfile(); image.MetaData.ExifProfile = new ExifProfile();
image.ExifProfile.SetValue(ExifTag.Orientation, orientation); image.MetaData.ExifProfile.SetValue(ExifTag.Orientation, orientation);
using (FileStream before = File.OpenWrite($"{path}/before-{file.FileName}")) using (FileStream before = File.OpenWrite($"{path}/before-{file.FileName}"))
using (FileStream after = File.OpenWrite($"{path}/after-{file.FileName}")) using (FileStream after = File.OpenWrite($"{path}/after-{file.FileName}"))

Loading…
Cancel
Save