From 266aad33eb46d869375566e398bfcabc0802b5aa Mon Sep 17 00:00:00 2001 From: dirk Date: Sat, 13 Aug 2016 18:54:04 +0200 Subject: [PATCH] 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 --- src/ImageProcessorCore/Samplers/AutoOrient.cs | 84 +++++++++++++++++++ .../Samplers/Options/Orientation.cs | 20 +++++ .../Processors/Samplers/AutoOrientTests.cs | 60 +++++++++++++ tests/ImageProcessorCore.Tests/TestImages.cs | 3 + .../TestImages/Formats/Bmp/F.bmp | 3 + 5 files changed, 170 insertions(+) create mode 100644 src/ImageProcessorCore/Samplers/AutoOrient.cs create mode 100644 src/ImageProcessorCore/Samplers/Options/Orientation.cs create mode 100644 tests/ImageProcessorCore.Tests/Processors/Samplers/AutoOrientTests.cs create mode 100644 tests/ImageProcessorCore.Tests/TestImages/Formats/Bmp/F.bmp diff --git a/src/ImageProcessorCore/Samplers/AutoOrient.cs b/src/ImageProcessorCore/Samplers/AutoOrient.cs new file mode 100644 index 000000000..62c7a5584 --- /dev/null +++ b/src/ImageProcessorCore/Samplers/AutoOrient.cs @@ -0,0 +1,84 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore +{ + using Processors; + + /// + /// Extension methods for the type. + /// + public static partial class ImageExtensions + { + /// + /// Adjusts an image so that its orientation is suitable for viewing. + /// + /// The pixel format. + /// The packed format. long, float. + /// The image to crop. + /// The + public static Image AutoOrient(this Image source, ProgressEventHandler progressHandler = null) + where T : IPackedVector + 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(Image source) + where T : IPackedVector + 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; + } + } +} diff --git a/src/ImageProcessorCore/Samplers/Options/Orientation.cs b/src/ImageProcessorCore/Samplers/Options/Orientation.cs new file mode 100644 index 000000000..7ace8ab2d --- /dev/null +++ b/src/ImageProcessorCore/Samplers/Options/Orientation.cs @@ -0,0 +1,20 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore +{ + internal enum Orientation : ushort + { + Unknown = 0, + TopLeft = 1, + TopRight = 2, + BottomRight = 3, + BottomLeft = 4, + LeftTop = 5, + RightTop = 6, + RightBottom = 7, + LeftBottom = 8 + } +} diff --git a/tests/ImageProcessorCore.Tests/Processors/Samplers/AutoOrientTests.cs b/tests/ImageProcessorCore.Tests/Processors/Samplers/AutoOrientTests.cs new file mode 100644 index 000000000..e9d93ac3c --- /dev/null +++ b/tests/ImageProcessorCore.Tests/Processors/Samplers/AutoOrientTests.cs @@ -0,0 +1,60 @@ +// +// Copyright (c) James Jackson-South and contributors. +// Licensed under the Apache License, Version 2.0. +// + +namespace ImageProcessorCore.Tests +{ + using System.IO; + using Xunit; + + public class AutoOrientTests : FileTestBase + { + public static readonly TheoryData OrientationValues + = new TheoryData + { + { 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); + } + } + } + } + } +} \ No newline at end of file diff --git a/tests/ImageProcessorCore.Tests/TestImages.cs b/tests/ImageProcessorCore.Tests/TestImages.cs index f9c5bb243..f8379d9f0 100644 --- a/tests/ImageProcessorCore.Tests/TestImages.cs +++ b/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"; } } } diff --git a/tests/ImageProcessorCore.Tests/TestImages/Formats/Bmp/F.bmp b/tests/ImageProcessorCore.Tests/TestImages/Formats/Bmp/F.bmp new file mode 100644 index 000000000..d95598bef --- /dev/null +++ b/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