mirror of https://github.com/SixLabors/ImageSharp
Browse Source
Former-commit-id: 21db4ab00e856eae2f405ef0fba5637db1a309ac Former-commit-id: 6e9b3dd6524e5d7c811547f2808a95c720fe02b6 Former-commit-id: 291d39f6d5dcfed05b49bbfda0f78e4f48112d7faf/merge-core
43 changed files with 563 additions and 1184 deletions
@ -1,218 +0,0 @@ |
|||
<!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,249 @@ |
|||
// <copyright file="Color.cs" company="James South">
|
|||
// Copyright (c) James South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessor |
|||
{ |
|||
using System.Numerics; |
|||
|
|||
/// <summary>
|
|||
/// Represents a four-component color using red, green, blue, and alpha data.
|
|||
/// </summary>
|
|||
/// <remarks>
|
|||
/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance,
|
|||
/// as it avoids the need to create new values for modification operations.
|
|||
/// </remarks>
|
|||
public struct Color |
|||
{ |
|||
/// <summary>
|
|||
/// The backing vector for SIMD support.
|
|||
/// </summary>
|
|||
private Vector4 backingVector; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="r">
|
|||
/// The red component of this <see cref="Color"/>.
|
|||
/// </param>
|
|||
/// <param name="g">
|
|||
/// The green component of this <see cref="Color"/>.
|
|||
/// </param>
|
|||
/// <param name="b">
|
|||
/// The blue component of this <see cref="Color"/>.
|
|||
/// </param>
|
|||
/// <param name="a">
|
|||
/// The alpha component of this <see cref="Color"/>.
|
|||
/// </param>
|
|||
public Color(float r, float g, float b, float a) |
|||
: this() |
|||
{ |
|||
this.backingVector.X = r; |
|||
this.backingVector.Y = g; |
|||
this.backingVector.Z = b; |
|||
this.backingVector.W = a; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="Color"/> struct.
|
|||
/// </summary>
|
|||
/// <param name="vector">
|
|||
/// The vector.
|
|||
/// </param>
|
|||
private Color(Vector4 vector) |
|||
{ |
|||
this.backingVector = vector; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the blue component of the color.
|
|||
/// </summary>
|
|||
public float B |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.X; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.X = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the green component of the color.
|
|||
/// </summary>
|
|||
public float G |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.Y; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.Y = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the red component of the color.
|
|||
/// </summary>
|
|||
public float R |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.Z; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.Z = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets or sets the alpha component of the color.
|
|||
/// </summary>
|
|||
public float A |
|||
{ |
|||
get |
|||
{ |
|||
return this.backingVector.W; |
|||
} |
|||
|
|||
set |
|||
{ |
|||
this.backingVector.W = value; |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets this color with the component values clamped from 0 to 1.
|
|||
/// </summary>
|
|||
public Color Limited |
|||
{ |
|||
get |
|||
{ |
|||
float r = this.R.Clamp(0, 1); |
|||
float g = this.G.Clamp(0, 1); |
|||
float b = this.B.Clamp(0, 1); |
|||
float a = this.A.Clamp(0, 1); |
|||
return new Color(r, g, b, a); |
|||
} |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a
|
|||
/// <see cref="Bgra32"/>.
|
|||
/// </summary>
|
|||
/// <param name="color">
|
|||
/// The instance of <see cref="Color"/> to convert.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// An instance of <see cref="Bgra32"/>.
|
|||
/// </returns>
|
|||
public static implicit operator Color(Bgra32 color) |
|||
{ |
|||
return new Color(color.R / 255f, color.G / 255f, color.B / 255f, color.A / 255f); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the product of multiplying a color by a given factor.
|
|||
/// </summary>
|
|||
/// <param name="color">The color.</param>
|
|||
/// <param name="factor">The multiplication factor.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator *(Color color, float factor) |
|||
{ |
|||
return new Color(color.backingVector * factor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the product of multiplying a color by a given factor.
|
|||
/// </summary>
|
|||
/// <param name="factor">The multiplication factor.</param>
|
|||
/// <param name="color">The color.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator *(float factor, Color color) |
|||
{ |
|||
return new Color(color.backingVector * factor); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the product of multiplying two colors.
|
|||
/// </summary>
|
|||
/// <param name="left">The color on the left hand of the operand.</param>
|
|||
/// <param name="right">The color on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator *(Color left, Color right) |
|||
{ |
|||
return new Color(left.backingVector * right.backingVector); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the sum of adding two colors.
|
|||
/// </summary>
|
|||
/// <param name="left">The color on the left hand of the operand.</param>
|
|||
/// <param name="right">The color on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator +(Color left, Color right) |
|||
{ |
|||
return new Color(left.R + right.R, left.G + right.G, left.B + right.B, left.A + right.A); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Computes the difference left by subtracting one color from another.
|
|||
/// </summary>
|
|||
/// <param name="left">The color on the left hand of the operand.</param>
|
|||
/// <param name="right">The color on the right hand of the operand.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color operator -(Color left, Color right) |
|||
{ |
|||
return new Color(left.R - right.R, left.G - right.G, left.B - right.B, left.A - right.A); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Returns a new color whose components are the average of the components of first and second.
|
|||
/// </summary>
|
|||
/// <param name="first">The first color.</param>
|
|||
/// <param name="second">The second color.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color Average(Color first, Color second) |
|||
{ |
|||
return new Color((first.backingVector + second.backingVector) * .5f); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Linearly interpolates from one color to another based on the given amount.
|
|||
/// </summary>
|
|||
/// <param name="from">The first color value.</param>
|
|||
/// <param name="to">The second color value.</param>
|
|||
/// <param name="amount">
|
|||
/// The weight value. At amount = 0, "from" is returned, at amount = 1, "to" is returned.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="Color"/>
|
|||
/// </returns>
|
|||
public static Color Lerp(Color from, Color to, float amount) |
|||
{ |
|||
amount = amount.Clamp(0f, 1f); |
|||
|
|||
return (from * (1 - amount)) + (to * amount); |
|||
} |
|||
} |
|||
} |
|||
@ -1,132 +0,0 @@ |
|||
// <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); |
|||
} |
|||
} |
|||
} |
|||
@ -1,193 +0,0 @@ |
|||
// <copyright file="PixelOperations.cs" company="James South">
|
|||
// Copyright (c) James South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessor |
|||
{ |
|||
using System; |
|||
|
|||
/// <summary>
|
|||
/// Performs per-pixel operations.
|
|||
/// </summary>
|
|||
public static class PixelOperations |
|||
{ |
|||
/// <summary>
|
|||
/// The array of bytes representing each possible value of color component
|
|||
/// converted from sRGB to the linear color space.
|
|||
/// </summary>
|
|||
private static readonly Lazy<byte[]> LinearBytes = new Lazy<byte[]>(GetLinearBytes); |
|||
|
|||
/// <summary>
|
|||
/// The array of bytes representing each possible value of color component
|
|||
/// converted from linear to the sRGB color space.
|
|||
/// </summary>
|
|||
private static readonly Lazy<byte[]> SrgbBytes = new Lazy<byte[]>(GetSrgbBytes); |
|||
|
|||
/// <summary>
|
|||
/// The array of bytes representing each possible value of color component
|
|||
/// converted from gamma to the linear color space.
|
|||
/// </summary>
|
|||
private static readonly Lazy<byte[]> LinearGammaBytes = new Lazy<byte[]>(GetLinearGammaBytes); |
|||
|
|||
/// <summary>
|
|||
/// The array of bytes representing each possible value of color component
|
|||
/// converted from linear to the gamma color space.
|
|||
/// </summary>
|
|||
private static readonly Lazy<byte[]> GammaLinearBytes = new Lazy<byte[]>(GetGammaLinearBytes); |
|||
|
|||
/// <summary>
|
|||
/// Converts an pixel from an sRGB color-space to the equivalent linear color-space.
|
|||
/// </summary>
|
|||
/// <param name="composite">
|
|||
/// The <see cref="Bgra"/> to convert.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="Bgra"/>.
|
|||
/// </returns>
|
|||
public static Bgra ToLinear(Bgra composite) |
|||
{ |
|||
// Create only once and lazily.
|
|||
// byte[] ramp = LinearGammaBytes.Value;
|
|||
byte[] ramp = LinearBytes.Value; |
|||
|
|||
return new Bgra(ramp[composite.B], ramp[composite.G], ramp[composite.R], composite.A); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Converts a pixel from a linear color-space to the equivalent sRGB color-space.
|
|||
/// </summary>
|
|||
/// <param name="linear">
|
|||
/// The <see cref="Bgra"/> to convert.
|
|||
/// </param>
|
|||
/// <returns>
|
|||
/// The <see cref="Bgra"/>.
|
|||
/// </returns>
|
|||
public static Bgra ToSrgb(Bgra linear) |
|||
{ |
|||
// Create only once and lazily.
|
|||
// byte[] ramp = GammaLinearBytes.Value;
|
|||
byte[] ramp = SrgbBytes.Value; |
|||
|
|||
return new Bgra(ramp[linear.B], ramp[linear.G], ramp[linear.R], linear.A); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an array of bytes representing each possible value of color component
|
|||
/// converted from sRGB to the linear color space.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// The <see cref="T:byte[]"/>.
|
|||
/// </returns>
|
|||
private static byte[] GetLinearBytes() |
|||
{ |
|||
byte[] ramp = new byte[256]; |
|||
for (int x = 0; x < 256; ++x) |
|||
{ |
|||
byte val = (255f * SrgbToLinear(x / 255f)).ToByte(); |
|||
ramp[x] = val; |
|||
} |
|||
|
|||
return ramp; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an array of bytes representing each possible value of color component
|
|||
/// converted from linear to the sRGB color space.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// The <see cref="T:byte[]"/>.
|
|||
/// </returns>
|
|||
private static byte[] GetSrgbBytes() |
|||
{ |
|||
byte[] ramp = new byte[256]; |
|||
for (int x = 0; x < 256; ++x) |
|||
{ |
|||
byte val = (255f * LinearToSrgb(x / 255f)).ToByte(); |
|||
ramp[x] = val; |
|||
} |
|||
|
|||
return ramp; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the correct linear value from an sRGB signal.
|
|||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|||
/// </summary>
|
|||
/// <param name="signal">The signal value to convert.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/>.
|
|||
/// </returns>
|
|||
private static float SrgbToLinear(float signal) |
|||
{ |
|||
float a = 0.055f; |
|||
|
|||
if (signal <= 0.04045) |
|||
{ |
|||
return signal / 12.92f; |
|||
} |
|||
|
|||
return (float)Math.Pow((signal + a) / (1 + a), 2.4); |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets the correct sRGB value from an linear signal.
|
|||
/// <see href="http://www.4p8.com/eric.brasseur/gamma.html#formulas"/>
|
|||
/// <see href="http://entropymine.com/imageworsener/srgbformula/"/>
|
|||
/// </summary>
|
|||
/// <param name="signal">The signal value to convert.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="float"/>.
|
|||
/// </returns>
|
|||
private static float LinearToSrgb(float signal) |
|||
{ |
|||
float a = 0.055f; |
|||
|
|||
if (signal <= 0.0031308) |
|||
{ |
|||
return signal * 12.92f; |
|||
} |
|||
|
|||
return ((float)((1 + a) * Math.Pow(signal, 1 / 2.4f))) - a; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an array of bytes representing each possible value of color component
|
|||
/// converted from gamma to the linear color space.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// The <see cref="T:byte[]"/>.
|
|||
/// </returns>
|
|||
private static byte[] GetLinearGammaBytes() |
|||
{ |
|||
byte[] ramp = new byte[256]; |
|||
for (int x = 0; x < 256; ++x) |
|||
{ |
|||
byte val = (255f * Math.Pow(x / 255f, 2.2)).ToByte(); |
|||
ramp[x] = val; |
|||
} |
|||
|
|||
return ramp; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Gets an array of bytes representing each possible value of color component
|
|||
/// converted from linear to the gamma color space.
|
|||
/// </summary>
|
|||
/// <returns>
|
|||
/// The <see cref="T:byte[]"/>.
|
|||
/// </returns>
|
|||
private static byte[] GetGammaLinearBytes() |
|||
{ |
|||
byte[] ramp = new byte[256]; |
|||
for (int x = 0; x < 256; ++x) |
|||
{ |
|||
byte val = (255f * Math.Pow(x / 255f, 1 / 2.2)).ToByte(); |
|||
ramp[x] = val; |
|||
} |
|||
|
|||
return ramp; |
|||
} |
|||
} |
|||
} |
|||
@ -1,22 +1,27 @@ |
|||
namespace ImageProcessor.Samplers |
|||
// <copyright file="IResampler.cs" company="James South">
|
|||
// Copyright (c) James South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageProcessor.Samplers |
|||
{ |
|||
/// <summary>
|
|||
/// Encasulates an interpolation algorithm for resampling images.
|
|||
/// Encapsulates an interpolation algorithm for resampling images.
|
|||
/// </summary>
|
|||
public interface IResampler |
|||
{ |
|||
/// <summary>
|
|||
/// Gets the radius in which to sample pixels.
|
|||
/// </summary>
|
|||
double Radius { get; } |
|||
float Radius { get; } |
|||
|
|||
/// <summary>
|
|||
/// Gets the result of the interpolation algorithm.
|
|||
/// </summary>
|
|||
/// <param name="x">The value to process.</param>
|
|||
/// <returns>
|
|||
/// The <see cref="double"/>
|
|||
/// The <see cref="float"/>
|
|||
/// </returns>
|
|||
double GetValue(double x); |
|||
float GetValue(float x); |
|||
} |
|||
} |
|||
|
|||
@ -1,232 +0,0 @@ |
|||
// <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