mirror of https://github.com/SixLabors/ImageSharp
146 changed files with 1504 additions and 1146 deletions
@ -0,0 +1,100 @@ |
|||
// <copyright file="RotateFlip.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
|
|||
using ImageSharp.PixelFormats; |
|||
|
|||
using ImageSharp.Processing; |
|||
|
|||
/// <summary>
|
|||
/// Extension methods for the <see cref="Image{TPixel}"/> type.
|
|||
/// </summary>
|
|||
public static partial class ImageExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Mutates the image by applying the operations to it.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to rotate, flip, or both.</param>
|
|||
/// <param name="operations">The operations to perform on the source.</param>
|
|||
public static void Mutate<TPixel>(this Image<TPixel> source, Action<IImageOperations<TPixel>> operations) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
Guard.NotNull(operations, nameof(operations)); |
|||
|
|||
// TODO: add parameter to Configuration to configure how this is created, create an IImageOperationsFactory that cna be used to switch this out with a fake for testing
|
|||
var operationsRunner = new ImageOperations<TPixel>(source); |
|||
operations(operationsRunner); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Mutates the image by applying the operations to it.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to rotate, flip, or both.</param>
|
|||
/// <param name="operations">The operations to perform on the source.</param>
|
|||
public static void Mutate<TPixel>(this Image<TPixel> source, params IImageProcessor<TPixel>[] operations) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
Guard.NotNull(operations, nameof(operations)); |
|||
|
|||
// TODO: add parameter to Configuration to configure how this is created, create an IImageOperationsFactory that cna be used to switch this out with a fake for testing
|
|||
var operationsRunner = new ImageOperations<TPixel>(source); |
|||
operationsRunner.ApplyProcessors(operations); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Mutates the image by applying the operations to it.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to rotate, flip, or both.</param>
|
|||
/// <param name="operations">The operations to perform on the source.</param>
|
|||
/// <returns>Anew Image which has teh data from the <paramref name="source"/> but with the <paramref name="operations"/> applied.</returns>
|
|||
public static Image<TPixel> Generate<TPixel>(this Image<TPixel> source, Action<IImageOperations<TPixel>> operations) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
Guard.NotNull(operations, nameof(operations)); |
|||
var generated = new Image<TPixel>(source); |
|||
|
|||
// TODO: add parameter to Configuration to configure how this is created, create an IImageOperationsFactory that cna be used to switch this out with a fake for testing
|
|||
var operationsRunner = new ImageOperations<TPixel>(generated); |
|||
operations(operationsRunner); |
|||
return generated; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Mutates the image by applying the operations to it.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to rotate, flip, or both.</param>
|
|||
/// <param name="operations">The operations to perform on the source.</param>
|
|||
/// <returns>Anew Image which has teh data from the <paramref name="source"/> but with the <paramref name="operations"/> applied.</returns>
|
|||
public static Image<TPixel> Generate<TPixel>(this Image<TPixel> source, params IImageProcessor<TPixel>[] operations) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
Guard.NotNull(operations, nameof(operations)); |
|||
var generated = new Image<TPixel>(source); |
|||
|
|||
// TODO: add parameter to Configuration to configure how this is created, create an IImageOperationsFactory that cna be used to switch this out with a fake for testing
|
|||
var operationsRunner = new ImageOperations<TPixel>(generated); |
|||
operationsRunner.ApplyProcessors(operations); |
|||
return generated; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Mutates the image by applying the operations to it.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="source">The image to rotate, flip, or both.</param>
|
|||
/// <param name="operation">The operations to perform on the source.</param>
|
|||
/// <returns>returns the current optinoatins class to allow chaining of oprations.</returns>
|
|||
public static IImageOperations<TPixel> Run<TPixel>(this IImageOperations<TPixel> source, Action<Image<TPixel>> operation) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
=> source.ApplyProcessor(new DelegateImageProcessor<TPixel>(operation)); |
|||
} |
|||
} |
|||
@ -0,0 +1,36 @@ |
|||
// <copyright file="IImageFormat.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System; |
|||
using ImageSharp.Formats; |
|||
using ImageSharp.PixelFormats; |
|||
using ImageSharp.Processing; |
|||
using SixLabors.Primitives; |
|||
|
|||
/// <summary>
|
|||
/// The static collection of all the default image formats
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format</typeparam>
|
|||
public interface IImageOperations<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
/// <summary>
|
|||
/// Adds the processor to the current setr of image operations to be applied.
|
|||
/// </summary>
|
|||
/// <param name="processor">The processor to apply</param>
|
|||
/// <param name="rectangle">The area to apply it to</param>
|
|||
/// <returns>returns the current optinoatins class to allow chaining of oprations.</returns>
|
|||
IImageOperations<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle); |
|||
|
|||
/// <summary>
|
|||
/// Adds the processor to the current setr of image operations to be applied.
|
|||
/// </summary>
|
|||
/// <param name="processor">The processor to apply</param>
|
|||
/// <returns>returns the current optinoatins class to allow chaining of oprations.</returns>
|
|||
IImageOperations<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor); |
|||
} |
|||
} |
|||
@ -0,0 +1,62 @@ |
|||
// <copyright file="IImageFormat.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using System.Collections.Generic; |
|||
using ImageSharp.PixelFormats; |
|||
using ImageSharp.Processing; |
|||
using SixLabors.Primitives; |
|||
|
|||
/// <summary>
|
|||
/// The static collection of all the default image formats
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format</typeparam>
|
|||
internal class ImageOperations<TPixel> : IImageOperations<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
private readonly Image<TPixel> image; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ImageOperations{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="image">The image.</param>
|
|||
public ImageOperations(Image<TPixel> image) |
|||
{ |
|||
this.image = image; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IImageOperations<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor, Rectangle rectangle) |
|||
{ |
|||
// TODO : make this queue, and allow special processors managage the cloing operation for 'generate'
|
|||
// to allow things like resize to not need to retain an extra copy of image data in memory, and to
|
|||
// prevent an pixel copy operation
|
|||
this.image.ApplyProcessor(processor, rectangle); |
|||
return this; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public IImageOperations<TPixel> ApplyProcessor(IImageProcessor<TPixel> processor) |
|||
{ |
|||
return this.ApplyProcessor(processor, this.image.Bounds); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Applies a bluck colelctino of pressorce at once
|
|||
/// </summary>
|
|||
/// <param name="processors">Processors to apply</param>
|
|||
/// <returns>this </returns>
|
|||
public IImageOperations<TPixel> ApplyProcessors(IEnumerable<IImageProcessor<TPixel>> processors) |
|||
{ |
|||
foreach (var processor in processors) |
|||
{ |
|||
return this.ApplyProcessor(processor); |
|||
} |
|||
|
|||
return this; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,124 @@ |
|||
// <copyright file="LongRational.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp |
|||
{ |
|||
using SixLabors.Primitives; |
|||
|
|||
/// <summary>
|
|||
/// Represents a value in relation to a value on the image
|
|||
/// </summary>
|
|||
internal struct ValueSize |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ValueSize"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="value">The value.</param>
|
|||
/// <param name="type">The type.</param>
|
|||
public ValueSize(float value, ValueSizeType type) |
|||
{ |
|||
if (type != ValueSizeType.Absolute) |
|||
{ |
|||
Guard.MustBeBetweenOrEqualTo(value, 0, 1, nameof(value)); |
|||
} |
|||
|
|||
this.Value = value; |
|||
this.Type = type; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// The different vlaue types
|
|||
/// </summary>
|
|||
public enum ValueSizeType |
|||
{ |
|||
/// <summary>
|
|||
/// The value is the final return value
|
|||
/// </summary>
|
|||
Absolute, |
|||
|
|||
/// <summary>
|
|||
/// The value is a percentage of the Images Width
|
|||
/// </summary>
|
|||
PercentageOfWidth, |
|||
|
|||
/// <summary>
|
|||
/// The value is a percentage of the Images height
|
|||
/// </summary>
|
|||
PercentageOfHeight |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the value.
|
|||
/// </summary>
|
|||
public float Value { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the type.
|
|||
/// </summary>
|
|||
public ValueSizeType Type { get; } |
|||
|
|||
/// <summary>
|
|||
/// Implicitly converts a float into an absolute value
|
|||
/// </summary>
|
|||
/// <param name="d">the vlaue to use as the absolute figure.</param>
|
|||
public static implicit operator ValueSize(float d) |
|||
=> Absolute(d); |
|||
|
|||
/// <summary>
|
|||
/// Create a new ValueSize with as a PercentageOfWidth type with value set to percentage.
|
|||
/// </summary>
|
|||
/// <param name="percentage">The percentage.</param>
|
|||
/// <returns>a Values size with type PercentageOfWidth</returns>
|
|||
public static ValueSize PercentageOfWidth(float percentage) |
|||
{ |
|||
return new ValueSize(percentage, ValueSizeType.PercentageOfWidth); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a new ValueSize with as a PercentageOfHeight type with value set to percentage.
|
|||
/// </summary>
|
|||
/// <param name="percentage">The percentage.</param>
|
|||
/// <returns>a Values size with type PercentageOfHeight</returns>
|
|||
public static ValueSize PercentageOfHeight(float percentage) |
|||
{ |
|||
return new ValueSize(percentage, ValueSizeType.PercentageOfHeight); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Create a new ValueSize with as a Absolute type with value set to value.
|
|||
/// </summary>
|
|||
/// <param name="value">The value.</param>
|
|||
/// <returns>a Values size with type Absolute(</returns>
|
|||
public static ValueSize Absolute(float value) |
|||
{ |
|||
return new ValueSize(value, ValueSizeType.Absolute); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the specified size.
|
|||
/// </summary>
|
|||
/// <param name="size">The size.</param>
|
|||
/// <returns>The calucalted value</returns>
|
|||
public float Calculate(Size size) |
|||
{ |
|||
switch (this.Type) |
|||
{ |
|||
case ValueSizeType.PercentageOfWidth: |
|||
return this.Value * size.Width; |
|||
case ValueSizeType.PercentageOfHeight: |
|||
return this.Value * size.Height; |
|||
case ValueSizeType.Absolute: |
|||
default: |
|||
return this.Value; |
|||
} |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override string ToString() |
|||
{ |
|||
return $"{this.Value} - {this.Type}"; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,44 @@ |
|||
// <copyright file="DelegateImageProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Processing |
|||
{ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
using ImageSharp.PixelFormats; |
|||
using SixLabors.Primitives; |
|||
|
|||
/// <summary>
|
|||
/// Allows the application of processors to images.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
internal class DelegateImageProcessor<TPixel> : ImageProcessor<TPixel> |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
private readonly Action<Image<TPixel>> action; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="DelegateImageProcessor{TPixel}"/> class.
|
|||
/// </summary>
|
|||
/// <param name="action">The action.</param>
|
|||
public DelegateImageProcessor(Action<Image<TPixel>> action) |
|||
{ |
|||
this.action = action; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void BeforeImageApply(Image<TPixel> source, Rectangle sourceRectangle) |
|||
{ |
|||
this.action?.Invoke((Image<TPixel>)source); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(ImageBase<TPixel> source, Rectangle sourceRectangle) |
|||
{ |
|||
// no op, we did all we wanted to do inside BeforeImageApply
|
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,103 @@ |
|||
// <copyright file="FlipProcessor.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Processing.Processors |
|||
{ |
|||
using System; |
|||
using System.Threading.Tasks; |
|||
|
|||
using ImageSharp.Memory; |
|||
using ImageSharp.PixelFormats; |
|||
using SixLabors.Primitives; |
|||
|
|||
/// <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(ImageBase<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; |
|||
} |
|||
|
|||
var orientation = (Orientation)value.Value; |
|||
|
|||
source.MetaData.ExifProfile.SetValue(ExifTag.Orientation, (ushort)Orientation.TopLeft); |
|||
|
|||
return orientation; |
|||
} |
|||
} |
|||
} |
|||
Some files were not shown because too many files changed in this diff
Loading…
Reference in new issue