mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: 63f72c2f2fe3fcc93bc33dc34d53fd510c8b303f Former-commit-id: 62ee31e766620df396d7155a7b30bf09ce7ba4c3 Former-commit-id: ba93e7236c32f9b633c2d754781a641da27cc3c0pull/17/head
22 changed files with 967 additions and 344 deletions
@ -0,0 +1,218 @@ |
|||
<!DOCTYPE html><html xmlns:msxsl="urn:schemas-microsoft-com:xslt"> |
|||
<head> |
|||
<meta content="en-us" http-equiv="Content-Language" /><meta content="text/html; charset=utf-16" http-equiv="Content-Type" /><title _locID="PortabilityAnalysis0"> |
|||
.NET Portability Report |
|||
</title><style> |
|||
/* Body style, for the entire document */ |
|||
body |
|||
{ |
|||
background: #F3F3F4; |
|||
color: #1E1E1F; |
|||
font-family: "Segoe UI", Tahoma, Geneva, Verdana, sans-serif; |
|||
padding: 0; |
|||
margin: 0; |
|||
} |
|||
|
|||
/* Header1 style, used for the main title */ |
|||
h1 |
|||
{ |
|||
padding: 10px 0px 10px 10px; |
|||
font-size: 21pt; |
|||
background-color: #E2E2E2; |
|||
border-bottom: 1px #C1C1C2 solid; |
|||
color: #201F20; |
|||
margin: 0; |
|||
font-weight: normal; |
|||
} |
|||
|
|||
/* Header2 style, used for "Overview" and other sections */ |
|||
h2 |
|||
{ |
|||
font-size: 18pt; |
|||
font-weight: normal; |
|||
padding: 15px 0 5px 0; |
|||
margin: 0; |
|||
} |
|||
|
|||
/* Header3 style, used for sub-sections, such as project name */ |
|||
h3 |
|||
{ |
|||
font-weight: normal; |
|||
font-size: 15pt; |
|||
margin: 0; |
|||
padding: 15px 0 5px 0; |
|||
background-color: transparent; |
|||
} |
|||
|
|||
/* Color all hyperlinks one color */ |
|||
a |
|||
{ |
|||
color: #1382CE; |
|||
} |
|||
|
|||
/* Table styles */ |
|||
table |
|||
{ |
|||
border-spacing: 0 0; |
|||
border-collapse: collapse; |
|||
font-size: 10pt; |
|||
} |
|||
|
|||
table th |
|||
{ |
|||
background: #E7E7E8; |
|||
text-align: left; |
|||
text-decoration: none; |
|||
font-weight: normal; |
|||
padding: 3px 6px 3px 6px; |
|||
} |
|||
|
|||
table td |
|||
{ |
|||
vertical-align: top; |
|||
padding: 3px 6px 5px 5px; |
|||
margin: 0px; |
|||
border: 1px solid #E7E7E8; |
|||
background: #F7F7F8; |
|||
} |
|||
|
|||
/* Local link is a style for hyperlinks that link to file:/// content, there are lots so color them as 'normal' text until the user mouse overs */ |
|||
.localLink |
|||
{ |
|||
color: #1E1E1F; |
|||
background: #EEEEED; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
.localLink:hover |
|||
{ |
|||
color: #1382CE; |
|||
background: #FFFF99; |
|||
text-decoration: none; |
|||
} |
|||
|
|||
/* Center text, used in the over views cells that contain message level counts */ |
|||
.textCentered |
|||
{ |
|||
text-align: center; |
|||
} |
|||
|
|||
/* The message cells in message tables should take up all avaliable space */ |
|||
.messageCell |
|||
{ |
|||
width: 100%; |
|||
} |
|||
|
|||
/* Padding around the content after the h1 */ |
|||
#content |
|||
{ |
|||
padding: 0px 12px 12px 12px; |
|||
} |
|||
|
|||
/* The overview table expands to width, with a max width of 97% */ |
|||
#overview table |
|||
{ |
|||
width: auto; |
|||
max-width: 75%; |
|||
} |
|||
|
|||
/* The messages tables are always 97% width */ |
|||
#messages table |
|||
{ |
|||
width: 97%; |
|||
} |
|||
|
|||
/* All Icons */ |
|||
.IconSuccessEncoded, .IconInfoEncoded, .IconWarningEncoded, .IconErrorEncoded |
|||
{ |
|||
min-width:18px; |
|||
min-height:18px; |
|||
background-repeat:no-repeat; |
|||
background-position:center; |
|||
} |
|||
|
|||
/* Success icon encoded */ |
|||
.IconSuccessEncoded |
|||
{ |
|||
/* Note: Do not delete the comment below. It is used to verify the correctness of the encoded image resource below before the product is released */ |
|||
/* [---XsltValidateInternal-Base64EncodedImage:IconSuccess#Begin#background-image: url(data:image/png;base64,#Separator#);#End#] */ |
|||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABPElEQVR4Xp1Tv0vDUBi8FqeA4NpBcBLcWnQSApncOnTo4FSnjP0DsnXpH5CxiwbHDg4Zuj4oOEXiJgiC4FDcCkLWmIMc1Pfw+eMgQ77v3Xf3Pe51YKGqqisAEwCR1TIAsiAIblSo6xrdHeJR85Xle3mdmCQKb0PsfqyxxzM8K15HZADl/H5+sHpZwYfxyRjTs+kWwKBx8yoHd2mRiuzF8mkJniWH/13u3Fjrs/EdhsdDFHGB/DLXEJBDLh1MWPAhPo1BLB4WX5yQywHR+m3tVe/t97D52CB/ziG0nIgD/qDuYg8WuCcVZ2YGwlJ3YDugkpR/VNcAEx6GEKhERSr71FuO4YCM4XBdwKvecjIlkSnsO0Hyp/GxSeJAdzBKzpOtnPwyyiPdAZhpZptT04tU+zk7s8czeges//s5C5+CwqrR4/gw+AAAAABJRU5ErkJggg==); |
|||
} |
|||
|
|||
/* Information icon encoded */ |
|||
.IconInfoEncoded |
|||
{ |
|||
/* Note: Do not delete the comment below. It is used to verify the correctness of the encoded image resource below before the product is released */ |
|||
/* [---XsltValidateInternal-Base64EncodedImage:IconInformation#Begin#background-image: url(data:image/png;base64,#Separator#);#End#] */ |
|||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABHElEQVR4Xs2TsUoDQRRF7wwoziokjZUKadInhdhukR9YP8DMX1hYW+QvdsXa/QHBbcXC7W0CamWTQnclFutceIQJwwaWNLlwm5k5d94M76mmaeCrrmsLYOocY12FcxZFUeozCqKqqgYA8uevv1H6VuPxcwlfk5N92KHBxfFeCSAxxswlYAW/Xr989x/mv9gkhtyMDhcAxgzRsp7flj8B/HF1RsMXq+NZMkopaHe7lbKxQUEIGbKsYNoGn969060hZBkQex/W8oRQwsQaW2o3Ago2SVcJUzAgY3N0lTCZZm+zPS8HB51gMmS1DEYyOz9acKO1D8JWTlafKIMxdhvlfdyT94Vv5h7P8Ky7nQzACmhvKq3zk3PjW9asz9D/1oigecsioooAAAAASUVORK5CYII=); |
|||
} |
|||
|
|||
/* Warning icon encoded */ |
|||
.IconWarningEncoded |
|||
{ |
|||
/* Note: Do not delete the comment below. It is used to verify the correctness of the encoded image resource below before the product is released */ |
|||
/* [---XsltValidateInternal-Base64EncodedImage:IconWarning#Begin#background-image: url(data:image/png;base64,#Separator#);#End#] */ |
|||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAACXBIWXMAAA7EAAAOxAGVKw4bAAAAx0lEQVR4XpWSMQ7CMAxFf4xAyBMLCxMrO8dhaBcuwdCJS3RJBw7SA/QGTCxdWJgiQYWKXJWKIXHIlyw5lqr34tQgEOdcBsCOx5yZK3hCCKdYXneQkh4pEfqzLfu+wVDSyyzFoJjfz9NB+pAF+eizx2Vruts0k15mPgvS6GYvpVtQhB61IB/dk6AF6fS4Ben0uIX5odtFe8Q/eW1KvFeH4e8khT6+gm5B+t3juyDt7n0jpe+CANTd+oTUjN/U3yVaABnSUjFz/gFq44JaVSCXeQAAAABJRU5ErkJggg==); |
|||
} |
|||
|
|||
/* Error icon encoded */ |
|||
.IconErrorEncoded |
|||
{ |
|||
/* Note: Do not delete the comment below. It is used to verify the correctness of the encoded image resource below before the product is released */ |
|||
/* [---XsltValidateInternal-Base64EncodedImage:IconError#Begin#background-image: url(data:image/png;base64,#Separator#);#End#] */ |
|||
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAABQElEQVR4XqWTvUoEQRCE6wYPZUA80AfwAQz23uCMjA7MDRQEIzPBVEyNTQUFIw00vcQTTMzuAh/AxEQQT8HF/3G/oGGnEUGuoNnd6qoZuqltyKEsyzVJq5I6rnUp6SjGeGhESikzzlc1eL7opfuVbrqbU1Zw9NCgtQMaZpY0eNnaaL2fHusvTK5vKu7sjSS1Y4y3QUA6K3e3Mau5UFDyMP7tYF9o8cAHZv68vipoIJg971PZIZ5HiwdvYGGvFVFHmGmZ2MxwmQYPXubPl9Up0tfoMQGetXd6mRbvhBw+boZ6WF7Mbv1+GsHRk0fQmPAH1GfmZirbCfDJ61tw3Px8/8pZsPAG4jlVhcPgZ7adwNWBB68lkRQWFiTgFlbnLY3DGGM7izIJIyT/jjIvEJw6fdJTc6krDzh6aMwMP9bvDH4ADSsa9uSWVJkAAAAASUVORK5CYII=); |
|||
} |
|||
</style> |
|||
</head><body> |
|||
<h1 _locid="PortabilityReport"> |
|||
.NET Portability Report |
|||
</h1><div id="content"> |
|||
<h2 _locid="SummaryTitle"> |
|||
<a name="Summary"></a>Summary |
|||
</h2><div id="summary"> |
|||
<table> |
|||
<tbody> |
|||
<tr> |
|||
<th>Assembly</th><th>.NET Core 5.0</th><th>.NET Framework 4.6.1</th><th>.NET Native 1.0</th><th>ASP.NET 5 1.0</th><th>Mono 3.3.0.0</th><th>Windows 8.1</th><th>Windows Phone 8.1</th> |
|||
</tr><tr> |
|||
<td><strong><a href="#ImageProcessor">ImageProcessor</a></strong></td><td class="textCentered">100%</td><td class="textCentered">99.7%</td><td class="textCentered">100%</td><td class="textCentered">100%</td><td class="textCentered">97.6%</td><td class="textCentered">97.9%</td><td class="textCentered">97.9%</td> |
|||
</tr> |
|||
</tbody> |
|||
</table> |
|||
</div><div id="details"> |
|||
<a name="ImageProcessor"></a><h3> |
|||
ImageProcessor |
|||
</h3><table> |
|||
<tbody> |
|||
<tr> |
|||
<th>Target type</th><th>.NET Core 5.0</th><th>.NET Framework 4.6.1</th><th>.NET Native 1.0</th><th>ASP.NET 5 1.0</th><th>Mono 3.3.0.0</th><th>Windows 8.1</th><th>Windows Phone 8.1</th><th>Recommended changes</th> |
|||
</tr><tr> |
|||
<td>System.Reflection.TypeInfo</td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td style="padding-left:2em">get_Assembly</td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td> |
|||
</tr><tr> |
|||
<td>System.Numerics.Vector4</td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td style="padding-left:2em">X</td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td style="padding-left:2em">Z</td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td style="padding-left:2em">Y</td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td style="padding-left:2em">W</td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td style="padding-left:2em">#ctor(System.Single,System.Single,System.Single,System.Single)</td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td> |
|||
</tr><tr> |
|||
<td>System.Array</td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td style="padding-left:2em">Empty``1</td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconSuccessEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td class="IconErrorEncoded"></td><td></td> |
|||
</tr><tr> |
|||
<td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td><td> </td> |
|||
</tr> |
|||
</tbody> |
|||
</table><a href="#Summary">Back to summary</a> |
|||
</div> |
|||
@ -0,0 +1,132 @@ |
|||
// <copyright file="ColorVector.cs" company="James South">
|
|||
// Copyright (c) James South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessor |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
public struct ColorVector |
|||
{ |
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private Vector4 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ColorVector"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="b">
|
|||
/// The blue component of this <see cref="ColorVector"/>.
|
|||
/// </param>
|
|||
/// <param name="g">
|
|||
/// The green component of this <see cref="ColorVector"/>.
|
|||
/// </param>
|
|||
/// <param name="r">
|
|||
/// The red component of this <see cref="ColorVector"/>.
|
|||
/// </param>
|
|||
/// <param name="a">
|
|||
/// The alpha component of this <see cref="ColorVector"/>.
|
|||
/// </param>
|
|||
public ColorVector(double b, double g, double r, double a) |
|||
: this((float)b, (float)g, (float)r, (float)a) |
|||
{ |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="ColorVector"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="b">
|
|||
/// The blue component of this <see cref="ColorVector"/>.
|
|||
/// </param>
|
|||
/// <param name="g">
|
|||
/// The green component of this <see cref="ColorVector"/>.
|
|||
/// </param>
|
|||
/// <param name="r">
|
|||
/// The red component of this <see cref="ColorVector"/>.
|
|||
/// </param>
|
|||
/// <param name="a">
|
|||
/// The alpha component of this <see cref="ColorVector"/>.
|
|||
/// </param>
|
|||
public ColorVector(float b, float g, float r, float a) |
|||
: this() |
|||
{ |
|||
this.backingVector.X = b; |
|||
this.backingVector.Y = g; |
|||
this.backingVector.Z = r; |
|||
this.backingVector.W = a; |
|||
} |
|||
|
|||
/// <summary> The color's blue component, between 0.0 and 1.0 </summary>
|
|||
public float B |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.X; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.X = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary> The color's green component, between 0.0 and 1.0 </summary>
|
|||
public float G |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.Y; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.Y = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary> The color's red component, between 0.0 and 1.0 </summary>
|
|||
public float R |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.Z; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.Z = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary> The color's alpha component, between 0.0 and 1.0 </summary>
|
|||
public float A |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.W; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.W = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="ColorVector"/> to a
|
|||
/// <see cref="Bgra"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="ColorVector"/> to convert.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Bgra"/>.
|
|||
/// </returns>
|
|||
public static implicit operator ColorVector(Bgra color) |
|||
{ |
|||
return new ColorVector(color.B / 255f, color.G / 255f, color.R / 255f, color.A / 255f); |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
// <copyright file="EnumerableExtensions.cs" company="James South">
|
|||
// Copyright (c) James South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessor |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
|
|||
/// <summary>
|
|||
/// Encapsulates a series of time saving extension methods to the <see cref="T:System.Collections.IEnumerable"/> interface.
|
|||
/// </summary>
|
|||
public static class EnumerableExtensions |
|||
{ |
|||
/// <summary>
|
|||
/// Generates a sequence of integral numbers within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="fromInclusive">
|
|||
/// The start index, inclusive.
|
|||
/// </param>
|
|||
/// <param name="toExclusive">
|
|||
/// The end index, exclusive.
|
|||
/// </param>
|
|||
/// <param name="step">
|
|||
/// The incremental step.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
|
|||
/// </returns>
|
|||
public static IEnumerable<int> SteppedRange(int fromInclusive, int toExclusive, int step) |
|||
{ |
|||
// Borrowed from Enumerable.Range
|
|||
long num = (fromInclusive + toExclusive) - 1L; |
|||
if ((toExclusive < 0) || (num > 0x7fffffffL)) |
|||
{ |
|||
throw new ArgumentOutOfRangeException(nameof(toExclusive)); |
|||
} |
|||
|
|||
return RangeIterator(fromInclusive, i => i < toExclusive, step); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Generates a sequence of integral numbers within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="fromInclusive">
|
|||
/// The start index, inclusive.
|
|||
/// </param>
|
|||
/// <param name="toDelegate">
|
|||
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index
|
|||
/// </param>
|
|||
/// <param name="step">
|
|||
/// The incremental step.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
|
|||
/// </returns>
|
|||
public static IEnumerable<int> SteppedRange(int fromInclusive, Func<int, bool> toDelegate, int step) |
|||
{ |
|||
return RangeIterator(fromInclusive, toDelegate, step); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Generates a sequence of integral numbers within a specified range.
|
|||
/// </summary>
|
|||
/// <param name="fromInclusive">
|
|||
/// The start index, inclusive.
|
|||
/// </param>
|
|||
/// <param name="toDelegate">
|
|||
/// A method that has one parameter and returns a <see cref="bool"/> calculating the end index
|
|||
/// </param>
|
|||
/// <param name="step">
|
|||
/// The incremental step.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="IEnumerable{Int32}"/> that contains a range of sequential integral numbers.
|
|||
/// </returns>
|
|||
private static IEnumerable<int> RangeIterator(int fromInclusive, Func<int, bool> toDelegate, int step) |
|||
{ |
|||
int i = fromInclusive; |
|||
while (toDelegate(i)) |
|||
{ |
|||
yield return i; |
|||
i += step; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,232 @@ |
|||
// <copyright file="Resize.cs" company="James South">
|
|||
// Copyright (c) James South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessor.Samplers |
|||
{ |
|||
using System; |
|||
using System.Collections.Generic; |
|||
using System.Threading.Tasks; |
|||
|
|||
/// <summary>
|
|||
/// Provides methods that allow the resizing of images using various resampling algorithms.
|
|||
/// </summary>
|
|||
public class Resize : ParallelImageProcessor |
|||
{ |
|||
/// <summary>
|
|||
/// The epsilon for comparing floating point numbers.
|
|||
/// </summary>
|
|||
private const float Epsilon = 0.0001f; |
|||
|
|||
/// <summary>
|
|||
/// The horizontal weights.
|
|||
/// </summary>
|
|||
private Weights[] horizontalWeights; |
|||
|
|||
/// <summary>
|
|||
/// The vertical weights.
|
|||
/// </summary>
|
|||
private Weights[] verticalWeights; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Resize"/> class.
|
|||
/// </summary>
|
|||
/// <param name="sampler">
|
|||
/// The sampler to perform the resize operation.
|
|||
/// </param>
|
|||
public Resize(IResampler sampler) |
|||
{ |
|||
Guard.NotNull(sampler, nameof(sampler)); |
|||
|
|||
this.Sampler = sampler; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the sampler to perform the resize operation.
|
|||
/// </summary>
|
|||
public IResampler Sampler { get; } |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void OnApply(Rectangle targetRectangle, Rectangle sourceRectangle) |
|||
{ |
|||
this.horizontalWeights = this.PrecomputeWeights(targetRectangle.Width, sourceRectangle.Width); |
|||
this.verticalWeights = this.PrecomputeWeights(targetRectangle.Height, sourceRectangle.Height); |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
protected override void Apply(ImageBase target, ImageBase source, Rectangle targetRectangle, Rectangle sourceRectangle, int startY, int endY) |
|||
{ |
|||
int targetY = targetRectangle.Y; |
|||
int targetBottom = targetRectangle.Bottom; |
|||
int startX = targetRectangle.X; |
|||
int endX = targetRectangle.Right; |
|||
|
|||
Parallel.For( |
|||
startY, |
|||
endY, |
|||
y => |
|||
{ |
|||
if (y >= targetY && y < targetBottom) |
|||
{ |
|||
List<Weight> verticalValues = this.verticalWeights[y].Values; |
|||
double verticalSum = this.verticalWeights[y].Sum; |
|||
|
|||
for (int x = startX; x < endX; x++) |
|||
{ |
|||
List<Weight> horizontalValues = this.horizontalWeights[x].Values; |
|||
double horizontalSum = this.horizontalWeights[x].Sum; |
|||
|
|||
// Destination color components
|
|||
double r = 0; |
|||
double g = 0; |
|||
double b = 0; |
|||
double a = 0; |
|||
|
|||
foreach (Weight yw in verticalValues) |
|||
{ |
|||
if (Math.Abs(yw.Value) < Epsilon) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
int originY = yw.Index; |
|||
|
|||
foreach (Weight xw in horizontalValues) |
|||
{ |
|||
if (Math.Abs(xw.Value) < Epsilon) |
|||
{ |
|||
continue; |
|||
} |
|||
|
|||
int originX = xw.Index; |
|||
Bgra sourceColor = source[originX, originY]; |
|||
//ColorVector sourceColor = PixelOperations.ToLinear(source[originX, originY]);
|
|||
|
|||
r += sourceColor.R * (yw.Value / verticalSum) * (xw.Value / horizontalSum); |
|||
g += sourceColor.G * (yw.Value / verticalSum) * (xw.Value / horizontalSum); |
|||
b += sourceColor.B * (yw.Value / verticalSum) * (xw.Value / horizontalSum); |
|||
a += sourceColor.A * (yw.Value / verticalSum) * (xw.Value / horizontalSum); |
|||
} |
|||
} |
|||
|
|||
// TODO: Double cast.
|
|||
Bgra destinationColor = new Bgra(b.ToByte(), g.ToByte(), r.ToByte(), a.ToByte()); |
|||
//Bgra destinationColor = PixelOperations.ToSrgb(new ColorVector(b, g, r, a));
|
|||
target[x, y] = destinationColor; |
|||
} |
|||
} |
|||
}); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the weights to apply at each pixel when resizing.
|
|||
/// </summary>
|
|||
/// <param name="destinationSize">The destination section size.</param>
|
|||
/// <param name="sourceSize">The source section size.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="T:Weights[]"/>.
|
|||
/// </returns>
|
|||
private Weights[] PrecomputeWeights(int destinationSize, int sourceSize) |
|||
{ |
|||
IResampler sampler = this.Sampler; |
|||
double du = sourceSize / (double)destinationSize; |
|||
double scale = du; |
|||
|
|||
if (scale < 1) |
|||
{ |
|||
scale = 1; |
|||
} |
|||
|
|||
double ru = Math.Ceiling(scale * sampler.Radius); |
|||
Weights[] result = new Weights[destinationSize]; |
|||
|
|||
for (int i = 0; i < destinationSize; i++) |
|||
{ |
|||
double fu = ((i + .5) * du) - 0.5; |
|||
int startU = (int)Math.Ceiling(fu - ru); |
|||
|
|||
if (startU < 0) |
|||
{ |
|||
startU = 0; |
|||
} |
|||
|
|||
int endU = (int)Math.Floor(fu + ru); |
|||
|
|||
if (endU > sourceSize - 1) |
|||
{ |
|||
endU = sourceSize - 1; |
|||
} |
|||
|
|||
double sum = 0; |
|||
result[i] = new Weights(); |
|||
|
|||
for (int a = startU; a <= endU; a++) |
|||
{ |
|||
double w = 255 * sampler.GetValue((a - fu) / scale); |
|||
|
|||
if (Math.Abs(w) > Epsilon) |
|||
{ |
|||
sum += w; |
|||
result[i].Values.Add(new Weight(a, w)); |
|||
} |
|||
} |
|||
|
|||
result[i].Sum = sum; |
|||
} |
|||
|
|||
return result; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Represents the weight to be added to a scaled pixel.
|
|||
/// </summary>
|
|||
protected struct Weight |
|||
{ |
|||
/// <summary>
|
|||
/// The pixel index.
|
|||
/// </summary>
|
|||
public readonly int Index; |
|||
|
|||
/// <summary>
|
|||
/// The result of the interpolation algorithm.
|
|||
/// </summary>
|
|||
public readonly double Value; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Weight"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="index">The index.</param>
|
|||
/// <param name="value">The value.</param>
|
|||
public Weight(int index, double value) |
|||
{ |
|||
this.Index = index; |
|||
this.Value = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Represents a collection of weights and their sum.
|
|||
/// </summary>
|
|||
protected class Weights |
|||
{ |
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Weights"/> class.
|
|||
/// </summary>
|
|||
public Weights() |
|||
{ |
|||
this.Values = new List<Weight>(); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the values.
|
|||
/// </summary>
|
|||
public List<Weight> Values { get; set; } |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the sum.
|
|||
/// </summary>
|
|||
public double Sum { get; set; } |
|||
} |
|||
} |
|||
} |
|||
Loading…
Reference in new issue