Browse Source

Added option to change the orientation of an image based on the information in the Exif profile.

Former-commit-id: ae4de1addaed801930aea365f4bc0a87d03f6e3f
Former-commit-id: bb1e39e2ef759b391e88b7f3fbfd98ea97913b3f
Former-commit-id: 97d2de47e68c5dafc524656ec3d95c1c1f72e7c2
af/merge-core
dirk 10 years ago
parent
commit
266aad33eb
  1. 84
      src/ImageProcessorCore/Samplers/AutoOrient.cs
  2. 20
      src/ImageProcessorCore/Samplers/Options/Orientation.cs
  3. 60
      tests/ImageProcessorCore.Tests/Processors/Samplers/AutoOrientTests.cs
  4. 3
      tests/ImageProcessorCore.Tests/TestImages.cs
  5. 3
      tests/ImageProcessorCore.Tests/TestImages/Formats/Bmp/F.bmp

84
src/ImageProcessorCore/Samplers/AutoOrient.cs

@ -0,0 +1,84 @@
// <copyright file="EntropyCrop.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
using Processors;
/// <summary>
/// Extension methods for the <see cref="Image{T,TP}"/> type.
/// </summary>
public static partial class ImageExtensions
{
/// <summary>
/// Adjusts an image so that its orientation is suitable for viewing.
/// </summary>
/// <typeparam name="T">The pixel format.</typeparam>
/// <typeparam name="TP">The packed format. <example>long, float.</example></typeparam>
/// <param name="source">The image to crop.</param>
/// <returns>The <see cref="Image"/></returns>
public static Image<T, TP> AutoOrient<T, TP>(this Image<T, TP> source, ProgressEventHandler progressHandler = null)
where T : IPackedVector<TP>
where TP : struct
{
Orientation orientation = GetExifOrientation(source);
switch (orientation)
{
case Orientation.Unknown:
case Orientation.TopLeft:
default:
return source;
case Orientation.TopRight:
return source.Flip(FlipType.Horizontal, progressHandler);
case Orientation.BottomRight:
return source.Rotate(RotateType.Rotate180, progressHandler);
case Orientation.BottomLeft:
return source.Flip(FlipType.Vertical, progressHandler);
case Orientation.LeftTop:
return source
.Rotate(RotateType.Rotate90, progressHandler)
.Flip(FlipType.Horizontal, progressHandler);
case Orientation.RightTop:
return source.Rotate(RotateType.Rotate90, progressHandler);
case Orientation.RightBottom:
return source
.Flip(FlipType.Vertical, progressHandler)
.Rotate(RotateType.Rotate270, progressHandler);
case Orientation.LeftBottom:
return source.Rotate(RotateType.Rotate270, progressHandler);
}
}
private static Orientation GetExifOrientation<T, TP>(Image<T, TP> source)
where T : IPackedVector<TP>
where TP : struct
{
if (source.ExifProfile == null)
{
return Orientation.Unknown;
}
ExifValue value = source.ExifProfile.GetValue(ExifTag.Orientation);
if (value == null)
{
return Orientation.Unknown;
}
Orientation orientation = (Orientation)value.Value;
source.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft);
return orientation;
}
}
}

20
src/ImageProcessorCore/Samplers/Options/Orientation.cs

@ -0,0 +1,20 @@
// <copyright file="AnchorPosition.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore
{
internal enum Orientation : ushort
{
Unknown = 0,
TopLeft = 1,
TopRight = 2,
BottomRight = 3,
BottomLeft = 4,
LeftTop = 5,
RightTop = 6,
RightBottom = 7,
LeftBottom = 8
}
}

60
tests/ImageProcessorCore.Tests/Processors/Samplers/AutoOrientTests.cs

@ -0,0 +1,60 @@
// <copyright file="RotateFlipTest.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageProcessorCore.Tests
{
using System.IO;
using Xunit;
public class AutoOrientTests : FileTestBase
{
public static readonly TheoryData<RotateType, FlipType, ushort> OrientationValues
= new TheoryData<RotateType, FlipType, ushort>
{
{ RotateType.None, FlipType.None, 0 },
{ RotateType.None, FlipType.None, 1 },
{ RotateType.None, FlipType.Horizontal, 2 },
{ RotateType.Rotate180, FlipType.None, 3 },
{ RotateType.Rotate180, FlipType.Horizontal, 4 },
{ RotateType.Rotate90, FlipType.Horizontal, 5 },
{ RotateType.Rotate270, FlipType.None, 6 },
{ RotateType.Rotate90, FlipType.Vertical, 7 },
{ RotateType.Rotate90, FlipType.None, 8 },
};
[Theory]
[MemberData("OrientationValues")]
public void ImageShouldFlip(RotateType rotateType, FlipType flipType, ushort orientation)
{
const string path = "TestOutput/AutoOrient";
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
string file = TestImages.Bmp.F;
using (FileStream stream = File.OpenRead(file))
{
string filename = Path.GetFileNameWithoutExtension(file) + "-" + orientation + Path.GetExtension(file);
Image image = new Image(stream);
image.ExifProfile = new ExifProfile();
image.ExifProfile.SetValue(ExifTag.Orientation, orientation);
using (FileStream before = File.OpenWrite($"{path}/before-{filename}"))
{
using (FileStream after = File.OpenWrite($"{path}/after-{filename}"))
{
image.RotateFlip(rotateType, flipType)
.Save(before)
.AutoOrient()
.Save(after);
}
}
}
}
}
}

3
tests/ImageProcessorCore.Tests/TestImages.cs

@ -38,6 +38,9 @@ namespace ImageProcessorCore.Tests
private static readonly string folder = "TestImages/Formats/Bmp/";
public static string Car { get { return folder + "Car.bmp"; } }
public static string F { get { return folder + "F.bmp"; } }
public static string Neg_height { get { return folder + "neg_height.bmp"; } }
}

3
tests/ImageProcessorCore.Tests/TestImages/Formats/Bmp/F.bmp

@ -0,0 +1,3 @@
version https://git-lfs.github.com/spec/v1
oid sha256:6da008d2b285b2db946e6d4ebf8569b0ddd4a05ef273b38304cb65afccac87b3
size 65502
Loading…
Cancel
Save