Browse Source

Convert OrientationMode into something usable.

pull/1976/head
James Jackson-South 4 years ago
parent
commit
d8372568e0
  1. 24
      src/ImageSharp/Metadata/Profiles/Exif/Values/ExifOrientationMode.cs
  2. 36
      src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs
  3. 71
      tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs

24
src/ImageSharp/Processing/OrientationMode.cs → src/ImageSharp/Metadata/Profiles/Exif/Values/ExifOrientationMode.cs

@ -1,56 +1,56 @@
// Copyright (c) Six Labors.
// Copyright (c) Six Labors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Processing
namespace SixLabors.ImageSharp.Metadata.Profiles.Exif
{
/// <summary>
/// Enumerates the available orientation values supplied by EXIF metadata.
/// </summary>
internal enum OrientationMode : ushort
public static class ExifOrientationMode
{
/// <summary>
/// Unknown rotation.
/// </summary>
Unknown = 0,
public const ushort Unknown = 0;
/// <summary>
/// The 0th row at the top, the 0th column on the left.
/// </summary>
TopLeft = 1,
public const ushort TopLeft = 1;
/// <summary>
/// The 0th row at the top, the 0th column on the right.
/// </summary>
TopRight = 2,
public const ushort TopRight = 2;
/// <summary>
/// The 0th row at the bottom, the 0th column on the right.
/// </summary>
BottomRight = 3,
public const ushort BottomRight = 3;
/// <summary>
/// The 0th row at the bottom, the 0th column on the left.
/// </summary>
BottomLeft = 4,
public const ushort BottomLeft = 4;
/// <summary>
/// The 0th row on the left, the 0th column at the top.
/// </summary>
LeftTop = 5,
public const ushort LeftTop = 5;
/// <summary>
/// The 0th row at the right, the 0th column at the top.
/// </summary>
RightTop = 6,
public const ushort RightTop = 6;
/// <summary>
/// The 0th row on the right, the 0th column at the bottom.
/// </summary>
RightBottom = 7,
public const ushort RightBottom = 7;
/// <summary>
/// The 0th row on the left, the 0th column at the bottom.
/// </summary>
LeftBottom = 8
public const ushort LeftBottom = 8;
}
}

36
src/ImageSharp/Processing/Processors/Transforms/Linear/AutoOrientProcessor{TPixel}.cs

@ -28,42 +28,42 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// <inheritdoc/>
protected override void BeforeImageApply()
{
OrientationMode orientation = GetExifOrientation(this.Source);
ushort orientation = GetExifOrientation(this.Source);
Size size = this.SourceRectangle.Size;
switch (orientation)
{
case OrientationMode.TopRight:
case ExifOrientationMode.TopRight:
new FlipProcessor(FlipMode.Horizontal).Execute(this.Configuration, this.Source, this.SourceRectangle);
break;
case OrientationMode.BottomRight:
case ExifOrientationMode.BottomRight:
new RotateProcessor((int)RotateMode.Rotate180, size).Execute(this.Configuration, this.Source, this.SourceRectangle);
break;
case OrientationMode.BottomLeft:
case ExifOrientationMode.BottomLeft:
new FlipProcessor(FlipMode.Vertical).Execute(this.Configuration, this.Source, this.SourceRectangle);
break;
case OrientationMode.LeftTop:
case ExifOrientationMode.LeftTop:
new RotateProcessor((int)RotateMode.Rotate90, size).Execute(this.Configuration, this.Source, this.SourceRectangle);
new FlipProcessor(FlipMode.Horizontal).Execute(this.Configuration, this.Source, this.SourceRectangle);
break;
case OrientationMode.RightTop:
case ExifOrientationMode.RightTop:
new RotateProcessor((int)RotateMode.Rotate90, size).Execute(this.Configuration, this.Source, this.SourceRectangle);
break;
case OrientationMode.RightBottom:
case ExifOrientationMode.RightBottom:
new FlipProcessor(FlipMode.Vertical).Execute(this.Configuration, this.Source, this.SourceRectangle);
new RotateProcessor((int)RotateMode.Rotate270, size).Execute(this.Configuration, this.Source, this.SourceRectangle);
break;
case OrientationMode.LeftBottom:
case ExifOrientationMode.LeftBottom:
new RotateProcessor((int)RotateMode.Rotate270, size).Execute(this.Configuration, this.Source, this.SourceRectangle);
break;
case OrientationMode.Unknown:
case OrientationMode.TopLeft:
case ExifOrientationMode.Unknown:
case ExifOrientationMode.TopLeft:
default:
break;
}
@ -81,32 +81,32 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms
/// Returns the current EXIF orientation
/// </summary>
/// <param name="source">The image to auto rotate.</param>
/// <returns>The <see cref="OrientationMode"/></returns>
private static OrientationMode GetExifOrientation(Image<TPixel> source)
/// <returns>The <see cref="ushort"/></returns>
private static ushort GetExifOrientation(Image<TPixel> source)
{
if (source.Metadata.ExifProfile is null)
{
return OrientationMode.Unknown;
return ExifOrientationMode.Unknown;
}
IExifValue<ushort> value = source.Metadata.ExifProfile.GetValue(ExifTag.Orientation);
if (value is null)
{
return OrientationMode.Unknown;
return ExifOrientationMode.Unknown;
}
OrientationMode orientation;
ushort orientation;
if (value.DataType == ExifDataType.Short)
{
orientation = (OrientationMode)value.Value;
orientation = value.Value;
}
else
{
orientation = (OrientationMode)Convert.ToUInt16(value.Value);
orientation = Convert.ToUInt16(value.Value);
source.Metadata.ExifProfile.RemoveValue(ExifTag.Orientation);
}
source.Metadata.ExifProfile.SetValue(ExifTag.Orientation, (ushort)OrientationMode.TopLeft);
source.Metadata.ExifProfile.SetValue(ExifTag.Orientation, ExifOrientationMode.TopLeft);
return orientation;
}

71
tests/ImageSharp.Tests/Processing/Processors/Transforms/AutoOrientTests.cs

@ -18,42 +18,41 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
public const string FlipTestFile = TestImages.Bmp.F;
public static readonly TheoryData<ExifDataType, byte[]> InvalidOrientationValues
= new TheoryData<ExifDataType, byte[]>
{
{ ExifDataType.Byte, new byte[] { 1 } },
{ ExifDataType.SignedByte, new byte[] { 2 } },
{ ExifDataType.SignedShort, BitConverter.GetBytes((short)3) },
{ ExifDataType.Long, BitConverter.GetBytes(4U) },
{ ExifDataType.SignedLong, BitConverter.GetBytes(5) }
};
= new()
{
{ ExifDataType.Byte, new byte[] { 1 } },
{ ExifDataType.SignedByte, new byte[] { 2 } },
{ ExifDataType.SignedShort, BitConverter.GetBytes((short)3) },
{ ExifDataType.Long, BitConverter.GetBytes(4U) },
{ ExifDataType.SignedLong, BitConverter.GetBytes(5) }
};
public static readonly TheoryData<ushort> ExifOrientationValues = new TheoryData<ushort>
{
0,
1,
2,
3,
4,
5,
6,
7,
8
};
public static readonly TheoryData<ushort> ExifOrientationValues
= new()
{
ExifOrientationMode.Unknown,
ExifOrientationMode.TopLeft,
ExifOrientationMode.TopRight,
ExifOrientationMode.BottomRight,
ExifOrientationMode.BottomLeft,
ExifOrientationMode.LeftTop,
ExifOrientationMode.RightTop,
ExifOrientationMode.RightBottom,
ExifOrientationMode.LeftBottom
};
[Theory]
[WithFile(FlipTestFile, nameof(ExifOrientationValues), PixelTypes.Rgba32)]
public void AutoOrient_WorksForAllExifOrientations<TPixel>(TestImageProvider<TPixel> provider, ushort orientation)
where TPixel : unmanaged, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage())
{
image.Metadata.ExifProfile = new ExifProfile();
image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, orientation);
using Image<TPixel> image = provider.GetImage();
image.Metadata.ExifProfile = new ExifProfile();
image.Metadata.ExifProfile.SetValue(ExifTag.Orientation, orientation);
image.Mutate(x => x.AutoOrient());
image.DebugSave(provider, orientation, appendPixelTypeToFileName: false);
image.CompareToReferenceOutput(provider, orientation, appendPixelTypeToFileName: false);
}
image.Mutate(x => x.AutoOrient());
image.DebugSave(provider, orientation, appendPixelTypeToFileName: false);
image.CompareToReferenceOutput(provider, orientation, appendPixelTypeToFileName: false);
}
[Theory]
@ -76,19 +75,17 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms
// Change the number of components
bytes[20] = 1;
var orientationCodeData = new byte[8];
byte[] orientationCodeData = new byte[8];
Array.Copy(orientation, orientationCodeData, orientation.Length);
ulong orientationCode = BitConverter.ToUInt64(orientationCodeData, 0);
using (Image<TPixel> image = provider.GetImage())
using (Image<TPixel> reference = image.Clone())
{
image.Metadata.ExifProfile = new ExifProfile(bytes);
image.Mutate(x => x.AutoOrient());
image.DebugSave(provider, $"{dataType}-{orientationCode}", appendPixelTypeToFileName: false);
ImageComparer.Exact.VerifySimilarity(image, reference);
}
using Image<TPixel> image = provider.GetImage();
using Image<TPixel> reference = image.Clone();
image.Metadata.ExifProfile = new ExifProfile(bytes);
image.Mutate(x => x.AutoOrient());
image.DebugSave(provider, $"{dataType}-{orientationCode}", appendPixelTypeToFileName: false);
ImageComparer.Exact.VerifySimilarity(image, reference);
}
}
}

Loading…
Cancel
Save