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