Browse Source

Fix AutoOrientProcessor

af/merge-core
JimBobSquarePants 9 years ago
parent
commit
e4893e850a
  1. 3
      src/ImageSharp/DefaultInternalImageProcessorContext.cs
  2. 6
      src/ImageSharp/Image/ImageFrame{TPixel}.cs
  3. 1
      src/ImageSharp/Processing/Processors/ImageProcessor.cs
  4. 103
      src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs
  5. 110
      src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs
  6. 2
      src/ImageSharp/Processing/Transforms/AutoOrient.cs
  7. 2
      tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs

3
src/ImageSharp/DefaultInternalImageProcessorContext.cs

@ -54,8 +54,7 @@ namespace SixLabors.ImageSharp
// This will only work if the first processor applied is the cloning one thus
// realistically for this optermissation to work the resize must the first processor
// applied any only up processors will take the douple data path.
var cloningImageProcessor = processor as ICloningImageProcessor<TPixel>;
if (cloningImageProcessor != null)
if (processor is ICloningImageProcessor<TPixel> cloningImageProcessor)
{
this.destination = cloningImageProcessor.CloneAndApply(this.source, rectangle);
return this;

6
src/ImageSharp/Image/ImageFrame{TPixel}.cs

@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(pixelSource, nameof(pixelSource));
// Push my memory into the accessor (which in turn unpins the old buffer ready for the images use)
var newPixels = pixelSource.SwapBufferOwnership(this.pixelBuffer);
Buffer2D<TPixel> newPixels = pixelSource.SwapBufferOwnership(this.pixelBuffer);
this.pixelBuffer = newPixels;
}
@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp
int newWidth = pixelSource.Width;
int newHeight = pixelSource.Height;
var newPixels = pixelSource.pixelBuffer;
Buffer2D<TPixel> newPixels = pixelSource.pixelBuffer;
pixelSource.pixelBuffer = this.pixelBuffer;
@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp
{
for (int x = 0; x < target.Width; x++)
{
TPixel2 color = default(TPixel2);
var color = default(TPixel2);
color.PackFromVector4(scaleFunc(pixels[x, y].ToVector4()));
targetPixels[x, y] = color;
}

1
src/ImageSharp/Processing/Processors/ImageProcessor.cs

@ -25,7 +25,6 @@ namespace SixLabors.ImageSharp.Processing
foreach (ImageFrame<TPixel> sourceFrame in source.Frames)
{
this.BeforeApply(sourceFrame, sourceRectangle);
this.OnApply(sourceFrame, sourceRectangle);
this.AfterApply(sourceFrame, sourceRectangle);
}

103
src/ImageSharp/Processing/Processors/Transforms/AutoOrientProcessor.cs

@ -0,0 +1,103 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors
{
/// <summary>
/// Adjusts an image so that its orientation is suitable for viewing. Adjustments are based on EXIF metadata embedded in the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class AutoOrientProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <inheritdoc/>
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{
Orientation orientation = GetExifOrientation(source);
switch (orientation)
{
case Orientation.TopRight:
new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle);
break;
case Orientation.BottomRight:
new RotateProcessor<TPixel> { Angle = (int)RotateType.Rotate180, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.BottomLeft:
new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle);
break;
case Orientation.LeftTop:
new RotateProcessor<TPixel> { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle);
new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle);
break;
case Orientation.RightTop:
new RotateProcessor<TPixel> { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.RightBottom:
new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle);
new RotateProcessor<TPixel> { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.LeftBottom:
new RotateProcessor<TPixel> { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.Unknown:
case Orientation.TopLeft:
default:
break;
}
}
/// <inheritdoc />
protected override void OnApply(ImageFrame<TPixel> source, Rectangle sourceRectangle)
{
// Nothing required here
}
/// <summary>
/// Returns the current EXIF orientation
/// </summary>
/// <param name="source">The image to auto rotate.</param>
/// <returns>The <see cref="Orientation"/></returns>
private static Orientation GetExifOrientation(Image<TPixel> source)
{
if (source.MetaData.ExifProfile == null)
{
return Orientation.Unknown;
}
ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation);
if (value == null)
{
return Orientation.Unknown;
}
Orientation orientation;
if (value.DataType == ExifDataType.Short)
{
orientation = (Orientation)value.Value;
}
else
{
orientation = (Orientation)Convert.ToUInt16(value.Value);
source.MetaData.ExifProfile.RemoveValue(ExifTag.Orientation);
}
source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft);
return orientation;
}
}
}

110
src/ImageSharp/Processing/Processors/Transforms/AutoRotateProcessor.cs

@ -1,110 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
namespace SixLabors.ImageSharp.Processing.Processors
{
/// <summary>
/// Adjusts an image so that its orientation is suitable for viewing. Adjustments are based on EXIF metadata embedded in the image.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
internal class AutoRotateProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel>
{
/// <summary>
/// Initializes a new instance of the <see cref="AutoRotateProcessor{TPixel}"/> class.
/// </summary>
public AutoRotateProcessor()
{
}
/// <inheritdoc/>
protected override void OnApply(ImageFrame<TPixel> sourceBase, Rectangle sourceRectangle)
{
// can only apply to the origional image
var source = sourceBase as Image<TPixel>;
if (source != null)
{
Orientation orientation = GetExifOrientation(source);
switch (orientation)
{
case Orientation.TopRight:
new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle);
break;
case Orientation.BottomRight:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate180, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.BottomLeft:
new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle);
break;
case Orientation.LeftTop:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle);
new FlipProcessor<TPixel>(FlipType.Horizontal).Apply(source, sourceRectangle);
break;
case Orientation.RightTop:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate90, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.RightBottom:
new FlipProcessor<TPixel>(FlipType.Vertical).Apply(source, sourceRectangle);
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.LeftBottom:
new RotateProcessor<TPixel>() { Angle = (int)RotateType.Rotate270, Expand = false }.Apply(source, sourceRectangle);
break;
case Orientation.Unknown:
case Orientation.TopLeft:
default:
break;
}
}
}
/// <summary>
/// Returns the current EXIF orientation
/// </summary>
/// <param name="source">The image to auto rotate.</param>
/// <returns>The <see cref="Orientation"/></returns>
private static Orientation GetExifOrientation(Image<TPixel> source)
{
if (source.MetaData.ExifProfile == null)
{
return Orientation.Unknown;
}
ExifValue value = source.MetaData.ExifProfile.GetValue(ExifTag.Orientation);
if (value == null)
{
return Orientation.Unknown;
}
Orientation orientation;
if (value.DataType == ExifDataType.Short)
{
orientation = (Orientation)value.Value;
}
else
{
orientation = (Orientation)Convert.ToUInt16(value.Value);
source.MetaData.ExifProfile.RemoveValue(ExifTag.Orientation);
}
source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft);
return orientation;
}
}
}

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

@ -20,6 +20,6 @@ namespace SixLabors.ImageSharp
/// <returns>The <see cref="Image{TPixel}"/></returns>
public static IImageProcessingContext<TPixel> AutoOrient<TPixel>(this IImageProcessingContext<TPixel> source)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new Processing.Processors.AutoRotateProcessor<TPixel>());
=> source.ApplyProcessor(new Processing.Processors.AutoOrientProcessor<TPixel>());
}
}

2
tests/ImageSharp.Tests/Processing/Transforms/AutoOrientTests.cs

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms
public void AutoOrient_AutoRotateProcessor()
{
this.operations.AutoOrient();
this.Verify<AutoRotateProcessor<Rgba32>>();
this.Verify<AutoOrientProcessor<Rgba32>>();
}
}
}
Loading…
Cancel
Save