mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: 7d28a87716e4b7c2dea73bc0fb804873d30372f6 Former-commit-id: 433c2d3c310ed0e361c42601ae4432d97a074fcf Former-commit-id: abf2e280afbcc9bc0d02cdfe74921f2763ce0f8daf/merge-core
9 changed files with 532 additions and 38 deletions
@ -0,0 +1,58 @@ |
|||
// <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.Samplers |
|||
{ |
|||
/// <summary>
|
|||
/// Enumerated anchor positions to apply to resized images.
|
|||
/// </summary>
|
|||
public enum AnchorPosition |
|||
{ |
|||
/// <summary>
|
|||
/// Anchors the position of the image to the center of it's bounding container.
|
|||
/// </summary>
|
|||
Center, |
|||
|
|||
/// <summary>
|
|||
/// Anchors the position of the image to the top of it's bounding container.
|
|||
/// </summary>
|
|||
Top, |
|||
|
|||
/// <summary>
|
|||
/// Anchors the position of the image to the bottom of it's bounding container.
|
|||
/// </summary>
|
|||
Bottom, |
|||
|
|||
/// <summary>
|
|||
/// Anchors the position of the image to the left of it's bounding container.
|
|||
/// </summary>
|
|||
Left, |
|||
|
|||
/// <summary>
|
|||
/// Anchors the position of the image to the right of it's bounding container.
|
|||
/// </summary>
|
|||
Right, |
|||
|
|||
/// <summary>
|
|||
/// Anchors the position of the image to the top left side of it's bounding container.
|
|||
/// </summary>
|
|||
TopLeft, |
|||
|
|||
/// <summary>
|
|||
/// Anchors the position of the image to the top right side of it's bounding container.
|
|||
/// </summary>
|
|||
TopRight, |
|||
|
|||
/// <summary>
|
|||
/// Anchors the position of the image to the bottom right side of it's bounding container.
|
|||
/// </summary>
|
|||
BottomRight, |
|||
|
|||
/// <summary>
|
|||
/// Anchors the position of the image to the bottom left side of it's bounding container.
|
|||
/// </summary>
|
|||
BottomLeft |
|||
} |
|||
} |
|||
@ -0,0 +1,235 @@ |
|||
// <copyright file="ResizeHelper.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Samplers |
|||
{ |
|||
using System; |
|||
using System.Linq; |
|||
|
|||
/// <summary>
|
|||
/// Provides methods to help calculate the target rectangle when resizing using the
|
|||
/// <see cref="ResizeMode"/> enumeration.
|
|||
/// </summary>
|
|||
internal static class ResizeHelper |
|||
{ |
|||
/// <summary>
|
|||
/// Calculates the target location and bounds to perform the resize operation against.
|
|||
/// </summary>
|
|||
/// <param name="source">The source image.</param>
|
|||
/// <param name="options">The resize options.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Rectangle"/>.
|
|||
/// </returns>
|
|||
public static Rectangle CalculateTargetLocationAndBounds(ImageBase source, ResizeOptions options) |
|||
{ |
|||
switch (options.Mode) |
|||
{ |
|||
case ResizeMode.Pad: |
|||
return CalculatePadRectangle(source, options); |
|||
|
|||
// TODO: Additional modes
|
|||
// Default case ResizeMode.Crop
|
|||
default: |
|||
return CalculateCropRectangle(source, options); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the target rectangle for crop mode.
|
|||
/// </summary>
|
|||
/// <param name="source">The source image.</param>
|
|||
/// <param name="options">The resize options.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Rectangle"/>.
|
|||
/// </returns>
|
|||
private static Rectangle CalculateCropRectangle(ImageBase source, ResizeOptions options) |
|||
{ |
|||
int width = options.Size.Width; |
|||
int height = options.Size.Height; |
|||
|
|||
if (width <= 0 || height <= 0) |
|||
{ |
|||
return new Rectangle(0, 0, source.Width, source.Height); |
|||
} |
|||
|
|||
double ratio; |
|||
int sourceWidth = source.Width; |
|||
int sourceHeight = source.Height; |
|||
|
|||
int destinationX = 0; |
|||
int destinationY = 0; |
|||
int destinationWidth = width; |
|||
int destinationHeight = height; |
|||
|
|||
// Fractional variants for preserving aspect ratio.
|
|||
double percentHeight = Math.Abs(height / (double)sourceHeight); |
|||
double percentWidth = Math.Abs(width / (double)sourceWidth); |
|||
|
|||
if (percentHeight < percentWidth) |
|||
{ |
|||
ratio = percentWidth; |
|||
|
|||
if (options.CenterCoordinates.Any()) |
|||
{ |
|||
double center = -(ratio * sourceHeight) * options.CenterCoordinates.First(); |
|||
destinationY = (int)center + (height / 2); |
|||
|
|||
if (destinationY > 0) |
|||
{ |
|||
destinationY = 0; |
|||
} |
|||
|
|||
if (destinationY < (int)(height - (sourceHeight * ratio))) |
|||
{ |
|||
destinationY = (int)(height - (sourceHeight * ratio)); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
switch (options.Position) |
|||
{ |
|||
case AnchorPosition.Top: |
|||
case AnchorPosition.TopLeft: |
|||
case AnchorPosition.TopRight: |
|||
destinationY = 0; |
|||
break; |
|||
case AnchorPosition.Bottom: |
|||
case AnchorPosition.BottomLeft: |
|||
case AnchorPosition.BottomRight: |
|||
destinationY = (int)(height - (sourceHeight * ratio)); |
|||
break; |
|||
default: |
|||
destinationY = (int)((height - (sourceHeight * ratio)) / 2); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
destinationHeight = (int)Math.Ceiling(sourceHeight * percentWidth); |
|||
} |
|||
else |
|||
{ |
|||
ratio = percentHeight; |
|||
|
|||
if (options.CenterCoordinates.Any()) |
|||
{ |
|||
double center = -(ratio * sourceWidth) * options.CenterCoordinates.ToArray()[1]; |
|||
destinationX = (int)center + (width / 2); |
|||
|
|||
if (destinationX > 0) |
|||
{ |
|||
destinationX = 0; |
|||
} |
|||
|
|||
if (destinationX < (int)(width - (sourceWidth * ratio))) |
|||
{ |
|||
destinationX = (int)(width - (sourceWidth * ratio)); |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
switch (options.Position) |
|||
{ |
|||
case AnchorPosition.Left: |
|||
case AnchorPosition.TopLeft: |
|||
case AnchorPosition.BottomLeft: |
|||
destinationX = 0; |
|||
break; |
|||
case AnchorPosition.Right: |
|||
case AnchorPosition.TopRight: |
|||
case AnchorPosition.BottomRight: |
|||
destinationX = (int)(width - (sourceWidth * ratio)); |
|||
break; |
|||
default: |
|||
destinationX = (int)((width - (sourceWidth * ratio)) / 2); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
destinationWidth = (int)Math.Ceiling(sourceWidth * percentHeight); |
|||
} |
|||
|
|||
return new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Calculates the target rectangle for pad mode.
|
|||
/// </summary>
|
|||
/// <param name="source">The source image.</param>
|
|||
/// <param name="options">The resize options.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Rectangle"/>.
|
|||
/// </returns>
|
|||
private static Rectangle CalculatePadRectangle(ImageBase source, ResizeOptions options) |
|||
{ |
|||
int width = options.Size.Width; |
|||
int height = options.Size.Height; |
|||
|
|||
if (width <= 0 || height <= 0) |
|||
{ |
|||
return new Rectangle(0, 0, source.Width, source.Height); |
|||
} |
|||
|
|||
double ratio; |
|||
int sourceWidth = source.Width; |
|||
int sourceHeight = source.Height; |
|||
|
|||
int destinationX = 0; |
|||
int destinationY = 0; |
|||
int destinationWidth = width; |
|||
int destinationHeight = height; |
|||
|
|||
// Fractional variants for preserving aspect ratio.
|
|||
double percentHeight = Math.Abs(height / (double)sourceHeight); |
|||
double percentWidth = Math.Abs(width / (double)sourceWidth); |
|||
|
|||
if (percentHeight < percentWidth) |
|||
{ |
|||
ratio = percentHeight; |
|||
destinationWidth = Convert.ToInt32(sourceWidth * percentHeight); |
|||
|
|||
switch (options.Position) |
|||
{ |
|||
case AnchorPosition.Left: |
|||
case AnchorPosition.TopLeft: |
|||
case AnchorPosition.BottomLeft: |
|||
destinationX = 0; |
|||
break; |
|||
case AnchorPosition.Right: |
|||
case AnchorPosition.TopRight: |
|||
case AnchorPosition.BottomRight: |
|||
destinationX = (int)(width - (sourceWidth * ratio)); |
|||
break; |
|||
default: |
|||
destinationX = Convert.ToInt32((width - (sourceWidth * ratio)) / 2); |
|||
break; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
ratio = percentWidth; |
|||
destinationHeight = Convert.ToInt32(sourceHeight * percentWidth); |
|||
|
|||
switch (options.Position) |
|||
{ |
|||
case AnchorPosition.Top: |
|||
case AnchorPosition.TopLeft: |
|||
case AnchorPosition.TopRight: |
|||
destinationY = 0; |
|||
break; |
|||
case AnchorPosition.Bottom: |
|||
case AnchorPosition.BottomLeft: |
|||
case AnchorPosition.BottomRight: |
|||
destinationY = (int)(height - (sourceHeight * ratio)); |
|||
break; |
|||
default: |
|||
destinationY = (int)((height - (sourceHeight * ratio)) / 2); |
|||
break; |
|||
} |
|||
} |
|||
|
|||
return new Rectangle(destinationX, destinationY, destinationWidth, destinationHeight); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,47 @@ |
|||
// <copyright file="ResizeMode.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Samplers |
|||
{ |
|||
/// <summary>
|
|||
/// Enumerated resize modes to apply to resized images.
|
|||
/// </summary>
|
|||
public enum ResizeMode |
|||
{ |
|||
/// <summary>
|
|||
/// Crops the resized image to fit the bounds of its container.
|
|||
/// </summary>
|
|||
Crop, |
|||
|
|||
/// <summary>
|
|||
/// Pads the resized image to fit the bounds of its container.
|
|||
/// If only one dimension is passed, will maintain the original aspect ratio.
|
|||
/// </summary>
|
|||
Pad, |
|||
|
|||
/// <summary>
|
|||
/// Stretches the resized image to fit the bounds of its container.
|
|||
/// </summary>
|
|||
Stretch, |
|||
|
|||
/// <summary>
|
|||
/// Constrains the resized image to fit the bounds of its container maintaining
|
|||
/// the original aspect ratio.
|
|||
/// </summary>
|
|||
Max, |
|||
|
|||
/// <summary>
|
|||
/// Resizes the image until the shortest side reaches the set given dimension.
|
|||
/// </summary>
|
|||
Min, |
|||
|
|||
/// <summary>
|
|||
/// Pads the image to fit the bound of the container without resizing the
|
|||
/// original source.
|
|||
/// When downscaling, performs the same functionality as <see cref="ResizeMode.Pad"/>
|
|||
/// </summary>
|
|||
BoxPad |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
// <copyright file="ResizeOptions.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessorCore.Samplers |
|||
{ |
|||
using System.Collections.Generic; |
|||
using System.Linq; |
|||
|
|||
/// <summary>
|
|||
/// The resize options for resizing images against certain modes.
|
|||
/// </summary>
|
|||
public class ResizeOptions |
|||
{ |
|||
/// <summary>
|
|||
/// Gets or sets the resize mode.
|
|||
/// </summary>
|
|||
public ResizeMode Mode { get; set; } = ResizeMode.Crop; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the anchor position.
|
|||
/// </summary>
|
|||
public AnchorPosition Position { get; set; } = AnchorPosition.Center; |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the center coordinates.
|
|||
/// </summary>
|
|||
public IEnumerable<float> CenterCoordinates { get; set; } = Enumerable.Empty<float>(); |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the target size.
|
|||
/// </summary>
|
|||
public Size Size { get; set; } |
|||
|
|||
public IResampler Sampler { get; set; } = new BicubicResampler(); |
|||
|
|||
public bool Compand { get; set; } |
|||
} |
|||
} |
|||
Loading…
Reference in new issue