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