Browse Source

Adding basic EXIF property item manipulation

Former-commit-id: 499d99a0048d840c7434726d0776035d258faa4b
af/merge-core
James South 12 years ago
parent
commit
9373a5c045
  1. 2
      README.md
  2. 65
      src/ImageProcessor/ImageFactory.cs
  3. 2
      src/ImageProcessor/ImageProcessor.csproj
  4. 1107
      src/ImageProcessor/Imaging/ExifPropertyTag.cs
  5. 58
      src/ImageProcessor/Imaging/ExifPropertyTagType.cs
  6. 18
      src/ImageProcessor/Imaging/ImageUtils.cs
  7. 4
      src/ImageProcessor/Settings.StyleCop

2
README.md

@ -5,4 +5,4 @@ Imageprocessor is a lightweight library written in C# that allows you to manipul
It's fast, extensible, easy to use, comes bundled with some great features and is fully open source. It's fast, extensible, easy to use, comes bundled with some great features and is fully open source.
For full documentation please see [http://jimbobsquarepants.github.io/ImageProcessor/](http://jimbobsquarepants.github.io/ImageProcessor/) For full documentation please see [http://imageprocessor.org/](http://imageprocessor.org/)

65
src/ImageProcessor/ImageFactory.cs

@ -12,6 +12,7 @@ namespace ImageProcessor
{ {
#region Using #region Using
using System; using System;
using System.Collections.Concurrent;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using System.Drawing; using System.Drawing;
@ -19,7 +20,6 @@ namespace ImageProcessor
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using ImageProcessor.Extensions; using ImageProcessor.Extensions;
using ImageProcessor.Imaging; using ImageProcessor.Imaging;
using ImageProcessor.Imaging.Filters; using ImageProcessor.Imaging.Filters;
@ -37,6 +37,11 @@ namespace ImageProcessor
/// </summary> /// </summary>
private const int DefaultJpegQuality = 90; private const int DefaultJpegQuality = 90;
/// <summary>
/// Whether to preserve exif metadata
/// </summary>
private readonly bool preserveExifData;
/// <summary> /// <summary>
/// The backup image format. /// The backup image format.
/// </summary> /// </summary>
@ -66,6 +71,20 @@ namespace ImageProcessor
private bool isDisposed; private bool isDisposed;
#endregion #endregion
#region Constructors
/// <summary>
/// Initializes a new instance of the <see cref="ImageFactory"/> class.
/// </summary>
/// <param name="preserveExifData">
/// Whether to preserve exif metadata. Defaults to false.
/// </param>
public ImageFactory(bool preserveExifData = true)
{
this.preserveExifData = preserveExifData;
this.ExifPropertyItems = new ConcurrentDictionary<int, PropertyItem>();
}
#endregion
#region Destructors #region Destructors
/// <summary> /// <summary>
/// Finalizes an instance of the <see cref="T:ImageProcessor.ImageFactory">ImageFactory</see> class. /// Finalizes an instance of the <see cref="T:ImageProcessor.ImageFactory">ImageFactory</see> class.
@ -123,6 +142,11 @@ namespace ImageProcessor
} }
} }
/// <summary>
/// Gets or sets the exif property items.
/// </summary>
public ConcurrentDictionary<int, PropertyItem> ExifPropertyItems { get; set; }
/// <summary> /// <summary>
/// Gets or sets the original extension. /// Gets or sets the original extension.
/// </summary> /// </summary>
@ -157,6 +181,15 @@ namespace ImageProcessor
this.ImageFormat = this.Image.RawFormat; this.ImageFormat = this.Image.RawFormat;
this.backupImageFormat = this.ImageFormat; this.backupImageFormat = this.ImageFormat;
this.isIndexed = ImageUtils.IsIndexed(this.Image); this.isIndexed = ImageUtils.IsIndexed(this.Image);
if (this.preserveExifData)
{
foreach (PropertyItem propertyItem in this.Image.PropertyItems)
{
this.ExifPropertyItems[propertyItem.Id] = propertyItem;
}
}
this.ShouldProcess = true; this.ShouldProcess = true;
return this; return this;
@ -210,6 +243,15 @@ namespace ImageProcessor
this.OriginalExtension = Path.GetExtension(this.ImagePath); this.OriginalExtension = Path.GetExtension(this.ImagePath);
this.ImageFormat = imageFormat; this.ImageFormat = imageFormat;
this.isIndexed = ImageUtils.IsIndexed(this.Image); this.isIndexed = ImageUtils.IsIndexed(this.Image);
if (this.preserveExifData)
{
foreach (PropertyItem propertyItem in this.Image.PropertyItems)
{
this.ExifPropertyItems[propertyItem.Id] = propertyItem;
}
}
this.ShouldProcess = true; this.ShouldProcess = true;
} }
} }
@ -419,7 +461,7 @@ namespace ImageProcessor
return this; return this;
} }
/// <summary> /// <summary>
/// Applies a filter to the current image. /// Applies a filter to the current image.
/// </summary> /// </summary>
@ -1032,6 +1074,25 @@ namespace ImageProcessor
{ {
this.Image = processor.Invoke(this); this.Image = processor.Invoke(this);
} }
// Set the property item information from any Exif metadata.
// We do this here so that they can be changed between processor methods.
if (this.preserveExifData)
{
foreach (KeyValuePair<int, PropertyItem> propertItem in this.ExifPropertyItems)
{
try
{
this.Image.SetPropertyItem(propertItem.Value);
}
// ReSharper disable once EmptyGeneralCatchClause
catch
{
// Do nothing. The image format does not handle EXIF data.
// TODO: empty catch is fierce code smell.
}
}
}
} }
#endregion #endregion
} }

2
src/ImageProcessor/ImageProcessor.csproj

@ -67,9 +67,11 @@
<Compile Include="Extensions\StringExtensions.cs" /> <Compile Include="Extensions\StringExtensions.cs" />
<Compile Include="ImageFactory.cs" /> <Compile Include="ImageFactory.cs" />
<Compile Include="Imaging\AnchorPosition.cs" /> <Compile Include="Imaging\AnchorPosition.cs" />
<Compile Include="Imaging\ExifPropertyTagType.cs" />
<Compile Include="Imaging\Convolution.cs" /> <Compile Include="Imaging\Convolution.cs" />
<Compile Include="Imaging\CropLayer.cs" /> <Compile Include="Imaging\CropLayer.cs" />
<Compile Include="Imaging\CropMode.cs" /> <Compile Include="Imaging\CropMode.cs" />
<Compile Include="Imaging\ExifPropertyTag.cs" />
<Compile Include="Imaging\Filters\MatrixFilterRegexAttribute.cs" /> <Compile Include="Imaging\Filters\MatrixFilterRegexAttribute.cs" />
<Compile Include="Imaging\Filters\MatrixFilters.cs" /> <Compile Include="Imaging\Filters\MatrixFilters.cs" />
<Compile Include="Imaging\GaussianLayer.cs" /> <Compile Include="Imaging\GaussianLayer.cs" />

1107
src/ImageProcessor/Imaging/ExifPropertyTag.cs

File diff suppressed because it is too large

58
src/ImageProcessor/Imaging/ExifPropertyTagType.cs

@ -0,0 +1,58 @@
// --------------------------------------------------------------------------------------------------------------------
// <copyright file="ExifPropertyTagType.cs" company="James South">
// Copyright (c) James South.
// Licensed under the Apache License, Version 2.0.
// </copyright>
// <summary>
// Specifies the data type of the values stored in the value data member of that same PropertyItem object.
// <see cref="http://msdn.microsoft.com/en-us/library/system.drawing.imaging.propertyitem.type.aspx" />
// </summary>
// --------------------------------------------------------------------------------------------------------------------
namespace ImageProcessor.Imaging
{
/// <summary>
/// Specifies the data type of the values stored in the value data member of that same PropertyItem object.
/// <see cref="http://msdn.microsoft.com/en-us/library/system.drawing.imaging.propertyitem.type.aspx"/>
/// </summary>
public enum ExifPropertyTagType : short
{
/// <summary>Specifies that the value data member is an array of bytes.</summary>
Byte = 1,
/// <summary>
/// Specifies that the value data member is a null-terminated ASCII string. If you set the type data member of a
/// PropertyItem object to ExifPropertyTagTypeASCII, you should set the length data member to the length of the string
/// including the NULL terminator. For example, the string HELLO would have a length of 6.
/// </summary>
ASCII = 2,
/// <summary>Specifies that the value data member is an array of unsigned short (16-bit) integers.</summary>
Int16 = 3,
/// <summary>Specifies that the value data member is an array of unsigned long (32-bit) integers.</summary>
Int32 = 4,
/// <summary>
/// Specifies that the value data member is an array of pairs of unsigned long integers. Each pair represents a
/// fraction; the first integer is the numerator and the second integer is the denominator.
/// </summary>
Rational = 5,
/// <summary>
/// Specifies that the value data member is an array of bytes that can hold values of any data type.
/// </summary>
Undefined = 7,
/// <summary>
/// Specifies that the value data member is an array of signed long (32-bit) integers.
/// </summary>
SLONG = 9,
/// <summary>
/// Specifies that the value data member is an array of pairs of signed long integers. Each pair represents a
/// fraction; the first integer is the numerator and the second integer is the denominator.
/// </summary>
SRational = 10
}
}

18
src/ImageProcessor/Imaging/ImageUtils.cs

@ -11,8 +11,12 @@
namespace ImageProcessor.Imaging namespace ImageProcessor.Imaging
{ {
#region Using #region Using
using System;
using System.Drawing; using System.Drawing;
using System.Drawing.Imaging; using System.Drawing.Imaging;
using System.Reflection;
#endregion #endregion
/// <summary> /// <summary>
@ -56,5 +60,19 @@ namespace ImageProcessor.Imaging
// ReSharper disable once BitwiseOperatorOnEnumWithoutFlags // ReSharper disable once BitwiseOperatorOnEnumWithoutFlags
return (image.PixelFormat & PixelFormat.Indexed) != 0; return (image.PixelFormat & PixelFormat.Indexed) != 0;
} }
/// <summary>
/// Uses reflection to allow the creation of an instance of <see cref="PropertyItem"/>.
/// </summary>
/// <returns>
/// The <see cref="PropertyItem"/>.
/// </returns>
public static PropertyItem CreatePropertyItem()
{
Type type = typeof(PropertyItem);
ConstructorInfo constructor = type.GetConstructor(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.Public, null, new Type[] { }, null);
return (PropertyItem)constructor.Invoke(null);
}
} }
} }

4
src/ImageProcessor/Settings.StyleCop

@ -2,7 +2,11 @@
<GlobalSettings> <GlobalSettings>
<CollectionProperty Name="RecognizedWords"> <CollectionProperty Name="RecognizedWords">
<Value>behaviour</Value> <Value>behaviour</Value>
<Value>chrominance</Value>
<Value>colour</Value> <Value>colour</Value>
<Value>enum</Value>
<Value>exif</Value>
<Value>halftoning</Value>
<Value>lomograph</Value> <Value>lomograph</Value>
<Value>octree</Value> <Value>octree</Value>
<Value>quantizer</Value> <Value>quantizer</Value>

Loading…
Cancel
Save