Browse Source

Merge branch 'master' of https://github.com/JimBobSquarePants/ImageSharp into jpeg-optimizations-experimental

Conflicts:
	tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs
pull/62/head
antonfirsov 10 years ago
parent
commit
7abc5bf102
  1. 6
      ImageSharp.ruleset
  2. 3
      ImageSharp.sln
  3. 3
      README.md
  4. 58
      src/ImageSharp/Colors/Color.cs
  5. 20
      src/ImageSharp/Colors/ColorspaceTransforms.cs
  6. 8
      src/ImageSharp/Colors/ComponentOrder.cs
  7. 58
      src/ImageSharp/Colors/PackedPixel/Alpha8.cs
  8. 60
      src/ImageSharp/Colors/PackedPixel/Argb.cs
  9. 60
      src/ImageSharp/Colors/PackedPixel/Bgr565.cs
  10. 60
      src/ImageSharp/Colors/PackedPixel/Bgra4444.cs
  11. 60
      src/ImageSharp/Colors/PackedPixel/Bgra5551.cs
  12. 60
      src/ImageSharp/Colors/PackedPixel/Byte4.cs
  13. 73
      src/ImageSharp/Colors/PackedPixel/HalfSingle.cs
  14. 73
      src/ImageSharp/Colors/PackedPixel/HalfVector2.cs
  15. 73
      src/ImageSharp/Colors/PackedPixel/HalfVector4.cs
  16. 32
      src/ImageSharp/Colors/PackedPixel/IPackedBytes.cs
  17. 79
      src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs
  18. 79
      src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs
  19. 79
      src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs
  20. 79
      src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs
  21. 64
      src/ImageSharp/Colors/PackedPixel/Rg32.cs
  22. 64
      src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs
  23. 64
      src/ImageSharp/Colors/PackedPixel/Rgba64.cs
  24. 79
      src/ImageSharp/Colors/PackedPixel/Short2.cs
  25. 91
      src/ImageSharp/Colors/PackedPixel/Short4.cs
  26. 17
      src/ImageSharp/Colors/Spaces/Bgra32.cs
  27. 24
      src/ImageSharp/Colors/Spaces/CieLab.cs
  28. 24
      src/ImageSharp/Colors/Spaces/CieXyz.cs
  29. 26
      src/ImageSharp/Colors/Spaces/Cmyk.cs
  30. 32
      src/ImageSharp/Colors/Spaces/Hsl.cs
  31. 32
      src/ImageSharp/Colors/Spaces/Hsv.cs
  32. 2
      src/ImageSharp/Colors/Spaces/IAlmostEquatable.cs
  33. 33
      src/ImageSharp/Colors/Spaces/YCbCr.cs
  34. 13
      src/ImageSharp/Colors/Vector4BlendTransforms.cs
  35. 18
      src/ImageSharp/Common/Constants.cs
  36. 17
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  37. 4
      src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs
  38. 4
      src/ImageSharp/Drawing/Processors/FillShapeProcessor.cs
  39. 7
      src/ImageSharp/Filters/Processors/Effects/BackgroundColorProcessor.cs
  40. 13
      src/ImageSharp/Filters/Processors/Transforms/RotateProcessor.cs
  41. 6
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  42. 8
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  43. 2
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  44. 7
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  45. 18
      src/ImageSharp/Formats/Jpg/Components/BlockQuad.cs
  46. 4
      src/ImageSharp/Formats/Jpg/Components/Decoder/Bits.cs
  47. 287
      src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs
  48. 70
      src/ImageSharp/Formats/Jpg/Utils/JpegUtils.cs
  49. 6
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  50. 2
      src/ImageSharp/Image/ImageBase{TColor}.cs
  51. 251
      src/ImageSharp/Image/PixelAccessor{TColor}.cs
  52. 114
      src/ImageSharp/Image/PixelArea{TColor}.cs
  53. 28
      src/ImageSharp/PixelAccessor.cs
  54. 50
      src/ImageSharp/Profiles/Exif/ExifTag.cs
  55. 14
      src/ImageSharp/Quantizers/Octree/OctreeQuantizer.cs
  56. 2
      src/ImageSharp/Quantizers/Palette/PaletteQuantizer.cs
  57. 15
      src/ImageSharp/Quantizers/Wu/WuQuantizer.cs
  58. 4
      src/ImageSharp/project.json
  59. 21
      tests/ImageSharp.Benchmarks/Image/CopyPixels.cs
  60. 2
      tests/ImageSharp.Tests/Colors/ColorConversionTests.cs
  61. 165
      tests/ImageSharp.Tests/Colors/PackedPixelTests.cs
  62. 18
      tests/ImageSharp.Tests/Common/ConstantsTests.cs
  63. 4
      tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs
  64. 6
      tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementations.cs
  65. 24
      tests/ImageSharp.Tests/Image/PixelAccessorTests.cs
  66. 12
      tests/ImageSharp.Tests/TestUtilities/TestUtilityExtensions.cs
  67. 8
      tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs
  68. 7
      tests/ImageSharp.Tests/project.json

6
ImageSharp.ruleset

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<RuleSet Name="ImageSharp" ToolsVersion="14.0">
<Rules AnalyzerId="StyleCop.Analyzers" RuleNamespace="StyleCop.Analyzers">
<Rule Id="SA1413" Action="None" />
</Rules>
</RuleSet>

3
ImageSharp.sln

@ -20,8 +20,11 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
build\dotnet-latest.ps1 = build\dotnet-latest.ps1 build\dotnet-latest.ps1 = build\dotnet-latest.ps1
features.md = features.md features.md = features.md
global.json = global.json global.json = global.json
ImageSharp.ruleset = ImageSharp.ruleset
NuGet.config = NuGet.config
build\package.json = build\package.json build\package.json = build\package.json
README.md = README.md README.md = README.md
Rebracer.xml = Rebracer.xml
Settings.StyleCop = Settings.StyleCop Settings.StyleCop = Settings.StyleCop
EndProjectSection EndProjectSection
EndProject EndProject

3
README.md

@ -98,3 +98,6 @@ Grand High Eternal Dictator
Core Team Core Team
- [Dirk Lemstra](https://github.com/dlemstra) - [Dirk Lemstra](https://github.com/dlemstra)
- [Jeavon Leopold](https://github.com/jeavon) - [Jeavon Leopold](https://github.com/jeavon)
- [Anton Firsov](https://github.com/antonfirsov)
- [Olivia Ifrim](https://github.com/olivif)
- [Scott Williams](https://github.com/tocsoft)

58
src/ImageSharp/Colors/Color.cs

@ -273,35 +273,37 @@ namespace ImageSharp
} }
/// <inheritdoc/> /// <inheritdoc/>
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
switch (componentOrder) bytes[startIndex] = this.R;
{ bytes[startIndex + 1] = this.G;
case ComponentOrder.ZYX: bytes[startIndex + 2] = this.B;
bytes[startIndex] = this.B; }
bytes[startIndex + 1] = this.G;
bytes[startIndex + 2] = this.R; /// <inheritdoc/>
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = this.B; bytes[startIndex] = this.R;
bytes[startIndex + 1] = this.G; bytes[startIndex + 1] = this.G;
bytes[startIndex + 2] = this.R; bytes[startIndex + 2] = this.B;
bytes[startIndex + 3] = this.A; bytes[startIndex + 3] = this.A;
break; }
case ComponentOrder.XYZ:
bytes[startIndex] = this.R; /// <inheritdoc/>
bytes[startIndex + 1] = this.G; public void ToZyxBytes(byte[] bytes, int startIndex)
bytes[startIndex + 2] = this.B; {
break; bytes[startIndex] = this.B;
case ComponentOrder.XYZW: bytes[startIndex + 1] = this.G;
bytes[startIndex] = this.R; bytes[startIndex + 2] = this.R;
bytes[startIndex + 1] = this.G; }
bytes[startIndex + 2] = this.B;
bytes[startIndex + 3] = this.A; /// <inheritdoc/>
break; public void ToZyxwBytes(byte[] bytes, int startIndex)
default: {
throw new NotSupportedException(); bytes[startIndex] = this.B;
} bytes[startIndex + 1] = this.G;
bytes[startIndex + 2] = this.R;
bytes[startIndex + 3] = this.A;
} }
/// <inheritdoc/> /// <inheritdoc/>

20
src/ImageSharp/Colors/ColorspaceTransforms.cs

@ -7,6 +7,7 @@ namespace ImageSharp
{ {
using System; using System;
using System.Numerics; using System.Numerics;
using Colors.Spaces;
/// <summary> /// <summary>
/// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255. /// Packed vector type containing four 8-bit unsigned normalized values ranging from 0 to 255.
@ -18,11 +19,6 @@ namespace ImageSharp
/// </remarks> /// </remarks>
public partial struct Color public partial struct Color
{ {
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.001F;
/// <summary> /// <summary>
/// Allows the implicit conversion of an instance of <see cref="Color"/> to a /// Allows the implicit conversion of an instance of <see cref="Color"/> to a
/// <see cref="Bgra32"/>. /// <see cref="Bgra32"/>.
@ -62,9 +58,9 @@ namespace ImageSharp
/// </returns> /// </returns>
public static implicit operator Color(YCbCr color) public static implicit operator Color(YCbCr color)
{ {
byte y = color.Y; float y = color.Y;
int cb = color.Cb - 128; float cb = color.Cb - 128;
int cr = color.Cr - 128; float cr = color.Cr - 128;
byte r = (byte)(y + (1.402F * cr)).Clamp(0, 255); byte r = (byte)(y + (1.402F * cr)).Clamp(0, 255);
byte g = (byte)(y - (0.34414F * cb) - (0.71414F * cr)).Clamp(0, 255); byte g = (byte)(y - (0.34414F * cb) - (0.71414F * cr)).Clamp(0, 255);
@ -109,12 +105,12 @@ namespace ImageSharp
float s = color.S; float s = color.S;
float v = color.V; float v = color.V;
if (Math.Abs(s) < Epsilon) if (Math.Abs(s) < Constants.Epsilon)
{ {
return new Color(v, v, v, 1); return new Color(v, v, v, 1);
} }
float h = (Math.Abs(color.H - 360) < Epsilon) ? 0 : color.H / 60; float h = (Math.Abs(color.H - 360) < Constants.Epsilon) ? 0 : color.H / 60;
int i = (int)Math.Truncate(h); int i = (int)Math.Truncate(h);
float f = h - i; float f = h - i;
@ -182,9 +178,9 @@ namespace ImageSharp
float s = color.S; float s = color.S;
float l = color.L; float l = color.L;
if (Math.Abs(l) > Epsilon) if (Math.Abs(l) > Constants.Epsilon)
{ {
if (Math.Abs(s) < Epsilon) if (Math.Abs(s) < Constants.Epsilon)
{ {
r = g = b = l; r = g = b = l;
} }

8
src/ImageSharp/Colors/ComponentOrder.cs

@ -13,21 +13,21 @@ namespace ImageSharp
/// <summary> /// <summary>
/// Z-> Y-> X order. Equivalent to B-> G-> R in <see cref="Color"/> /// Z-> Y-> X order. Equivalent to B-> G-> R in <see cref="Color"/>
/// </summary> /// </summary>
ZYX, Zyx,
/// <summary> /// <summary>
/// Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in <see cref="Color"/> /// Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in <see cref="Color"/>
/// </summary> /// </summary>
ZYXW, Zyxw,
/// <summary> /// <summary>
/// X-> Y-> Z order. Equivalent to R-> G-> B in <see cref="Color"/> /// X-> Y-> Z order. Equivalent to R-> G-> B in <see cref="Color"/>
/// </summary> /// </summary>
XYZ, Xyz,
/// <summary> /// <summary>
/// X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in <see cref="Color"/> /// X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in <see cref="Color"/>
/// </summary> /// </summary>
XYZW, Xyzw,
} }
} }

58
src/ImageSharp/Colors/PackedPixel/Alpha8.cs

@ -74,35 +74,37 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
switch (componentOrder) bytes[startIndex] = 0;
{ bytes[startIndex + 1] = 0;
case ComponentOrder.ZYX: bytes[startIndex + 2] = 0;
bytes[startIndex] = 0; }
bytes[startIndex + 1] = 0;
bytes[startIndex + 2] = 0; /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = 0; bytes[startIndex] = 0;
bytes[startIndex + 1] = 0; bytes[startIndex + 1] = 0;
bytes[startIndex + 2] = 0; bytes[startIndex + 2] = 0;
bytes[startIndex + 3] = this.PackedValue; bytes[startIndex + 3] = this.PackedValue;
break; }
case ComponentOrder.XYZ:
bytes[startIndex] = 0; /// <inheritdoc />
bytes[startIndex + 1] = 0; public void ToZyxBytes(byte[] bytes, int startIndex)
bytes[startIndex + 2] = 0; {
break; bytes[startIndex] = 0;
case ComponentOrder.XYZW: bytes[startIndex + 1] = 0;
bytes[startIndex] = 0; bytes[startIndex + 2] = 0;
bytes[startIndex + 1] = 0; }
bytes[startIndex + 2] = 0;
bytes[startIndex + 3] = this.PackedValue; /// <inheritdoc />
break; public void ToZyxwBytes(byte[] bytes, int startIndex)
default: {
throw new NotSupportedException(); bytes[startIndex] = 0;
} bytes[startIndex + 1] = 0;
bytes[startIndex + 2] = 0;
bytes[startIndex + 3] = this.PackedValue;
} }
/// <summary> /// <summary>

60
src/ImageSharp/Colors/PackedPixel/Argb.cs

@ -220,36 +220,38 @@ namespace ImageSharp
this.PackedValue = Pack(x, y, z, w); this.PackedValue = Pack(x, y, z, w);
} }
/// <inheritdoc/> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
switch (componentOrder) bytes[startIndex] = this.R;
{ bytes[startIndex + 1] = this.G;
case ComponentOrder.ZYX: bytes[startIndex + 2] = this.B;
bytes[startIndex] = this.B; }
bytes[startIndex + 1] = this.G;
bytes[startIndex + 2] = this.R; /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = this.B; bytes[startIndex] = this.R;
bytes[startIndex + 1] = this.G; bytes[startIndex + 1] = this.G;
bytes[startIndex + 2] = this.R; bytes[startIndex + 2] = this.B;
bytes[startIndex + 3] = this.A; bytes[startIndex + 3] = this.A;
break; }
case ComponentOrder.XYZ:
bytes[startIndex] = this.R; /// <inheritdoc />
bytes[startIndex + 1] = this.G; public void ToZyxBytes(byte[] bytes, int startIndex)
bytes[startIndex + 2] = this.B; {
break; bytes[startIndex] = this.B;
case ComponentOrder.XYZW: bytes[startIndex + 1] = this.G;
bytes[startIndex] = this.R; bytes[startIndex + 2] = this.R;
bytes[startIndex + 1] = this.G; }
bytes[startIndex + 2] = this.B;
bytes[startIndex + 3] = this.A; /// <inheritdoc />
break; public void ToZyxwBytes(byte[] bytes, int startIndex)
default: {
throw new NotSupportedException(); bytes[startIndex] = this.B;
} bytes[startIndex + 1] = this.G;
bytes[startIndex + 2] = this.R;
bytes[startIndex + 3] = this.A;
} }
/// <inheritdoc/> /// <inheritdoc/>

60
src/ImageSharp/Colors/PackedPixel/Bgr565.cs

@ -96,37 +96,41 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4() * 255F; Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
}
/// <inheritdoc />
public void ToXyzwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
}
/// <inheritdoc />
public void ToZyxBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
}
switch (componentOrder) /// <inheritdoc />
{ public void ToZyxwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYX: {
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
break; bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
case ComponentOrder.ZYXW: bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
break;
case ComponentOrder.XYZ:
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
break;
case ComponentOrder.XYZW:
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
break;
default:
throw new NotSupportedException();
}
} }
/// <inheritdoc /> /// <inheritdoc />

60
src/ImageSharp/Colors/PackedPixel/Bgra4444.cs

@ -88,37 +88,41 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4() * 255F; Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
}
/// <inheritdoc />
public void ToXyzwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 3] = (byte)vector.W;
}
/// <inheritdoc />
public void ToZyxBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
switch (componentOrder) /// <inheritdoc />
{ public void ToZyxwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYX: {
bytes[startIndex] = (byte)vector.Z; Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex + 1] = (byte)vector.Y; bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 2] = (byte)vector.X; bytes[startIndex + 1] = (byte)vector.Y;
break; bytes[startIndex + 2] = (byte)vector.X;
case ComponentOrder.ZYXW: bytes[startIndex + 3] = (byte)vector.W;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
break;
case ComponentOrder.XYZ:
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
break;
case ComponentOrder.XYZW:
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 3] = (byte)vector.W;
break;
default:
throw new NotSupportedException();
}
} }
/// <inheritdoc /> /// <inheritdoc />

60
src/ImageSharp/Colors/PackedPixel/Bgra5551.cs

@ -88,37 +88,41 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4() * 255F; Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
}
/// <inheritdoc />
public void ToXyzwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 3] = (byte)vector.W;
}
/// <inheritdoc />
public void ToZyxBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
switch (componentOrder) /// <inheritdoc />
{ public void ToZyxwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYX: {
bytes[startIndex] = (byte)vector.Z; Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex + 1] = (byte)vector.Y; bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 2] = (byte)vector.X; bytes[startIndex + 1] = (byte)vector.Y;
break; bytes[startIndex + 2] = (byte)vector.X;
case ComponentOrder.ZYXW: bytes[startIndex + 3] = (byte)vector.W;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
break;
case ComponentOrder.XYZ:
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
break;
case ComponentOrder.XYZW:
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 3] = (byte)vector.W;
break;
default:
throw new NotSupportedException();
}
} }
/// <inheritdoc /> /// <inheritdoc />

60
src/ImageSharp/Colors/PackedPixel/Byte4.cs

@ -95,37 +95,41 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4(); Vector4 vector = this.ToVector4();
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
}
/// <inheritdoc />
public void ToXyzwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 3] = (byte)vector.W;
}
/// <inheritdoc />
public void ToZyxBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
switch (componentOrder) /// <inheritdoc />
{ public void ToZyxwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYX: {
bytes[startIndex] = (byte)vector.Z; Vector4 vector = this.ToVector4();
bytes[startIndex + 1] = (byte)vector.Y; bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 2] = (byte)vector.X; bytes[startIndex + 1] = (byte)vector.Y;
break; bytes[startIndex + 2] = (byte)vector.X;
case ComponentOrder.ZYXW: bytes[startIndex + 3] = (byte)vector.W;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
break;
case ComponentOrder.XYZ:
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
break;
case ComponentOrder.XYZW:
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 3] = (byte)vector.W;
break;
default:
throw new NotSupportedException();
}
} }
/// <inheritdoc /> /// <inheritdoc />

73
src/ImageSharp/Colors/PackedPixel/HalfSingle.cs

@ -97,40 +97,57 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4(); Vector4 vector = this.ToVector4();
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
switch (componentOrder) bytes[startIndex] = (byte)vector.X;
{ bytes[startIndex + 1] = (byte)vector.Y;
case ComponentOrder.ZYX: bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex] = (byte)vector.Z; }
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X; /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = (byte)vector.Z; Vector4 vector = this.ToVector4();
bytes[startIndex + 1] = (byte)vector.Y; vector *= MaxBytes;
bytes[startIndex + 2] = (byte)vector.X; vector += Half;
bytes[startIndex + 3] = (byte)vector.W; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
break;
case ComponentOrder.XYZ: bytes[startIndex] = (byte)vector.X;
bytes[startIndex] = (byte)vector.X; bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 1] = (byte)vector.Y; bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 2] = (byte)vector.Z; bytes[startIndex + 3] = (byte)vector.W;
break; }
case ComponentOrder.XYZW:
bytes[startIndex] = (byte)vector.X; /// <inheritdoc />
bytes[startIndex + 1] = (byte)vector.Y; public void ToZyxBytes(byte[] bytes, int startIndex)
bytes[startIndex + 2] = (byte)vector.Z; {
bytes[startIndex + 3] = (byte)vector.W; Vector4 vector = this.ToVector4();
break; vector *= MaxBytes;
default: vector += Half;
throw new NotSupportedException(); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
}
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
/// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
} }
/// <inheritdoc /> /// <inheritdoc />

73
src/ImageSharp/Colors/PackedPixel/HalfVector2.cs

@ -111,40 +111,57 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4(); Vector4 vector = this.ToVector4();
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
switch (componentOrder) bytes[startIndex] = (byte)vector.X;
{ bytes[startIndex + 1] = (byte)vector.Y;
case ComponentOrder.ZYX: bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex] = (byte)vector.Z; }
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X; /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = (byte)vector.Z; Vector4 vector = this.ToVector4();
bytes[startIndex + 1] = (byte)vector.Y; vector *= MaxBytes;
bytes[startIndex + 2] = (byte)vector.X; vector += Half;
bytes[startIndex + 3] = (byte)vector.W; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
break;
case ComponentOrder.XYZ: bytes[startIndex] = (byte)vector.X;
bytes[startIndex] = (byte)vector.X; bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 1] = (byte)vector.Y; bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 2] = (byte)vector.Z; bytes[startIndex + 3] = (byte)vector.W;
break; }
case ComponentOrder.XYZW:
bytes[startIndex] = (byte)vector.X; /// <inheritdoc />
bytes[startIndex + 1] = (byte)vector.Y; public void ToZyxBytes(byte[] bytes, int startIndex)
bytes[startIndex + 2] = (byte)vector.Z; {
bytes[startIndex + 3] = (byte)vector.W; Vector4 vector = this.ToVector4();
break; vector *= MaxBytes;
default: vector += Half;
throw new NotSupportedException(); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
}
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
/// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
} }
/// <inheritdoc /> /// <inheritdoc />

73
src/ImageSharp/Colors/PackedPixel/HalfVector4.cs

@ -105,40 +105,57 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4(); Vector4 vector = this.ToVector4();
vector *= MaxBytes; vector *= MaxBytes;
vector += Half; vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
switch (componentOrder) bytes[startIndex] = (byte)vector.X;
{ bytes[startIndex + 1] = (byte)vector.Y;
case ComponentOrder.ZYX: bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex] = (byte)vector.Z; }
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X; /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = (byte)vector.Z; Vector4 vector = this.ToVector4();
bytes[startIndex + 1] = (byte)vector.Y; vector *= MaxBytes;
bytes[startIndex + 2] = (byte)vector.X; vector += Half;
bytes[startIndex + 3] = (byte)vector.W; vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
break;
case ComponentOrder.XYZ: bytes[startIndex] = (byte)vector.X;
bytes[startIndex] = (byte)vector.X; bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 1] = (byte)vector.Y; bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex + 2] = (byte)vector.Z; bytes[startIndex + 3] = (byte)vector.W;
break; }
case ComponentOrder.XYZW:
bytes[startIndex] = (byte)vector.X; /// <inheritdoc />
bytes[startIndex + 1] = (byte)vector.Y; public void ToZyxBytes(byte[] bytes, int startIndex)
bytes[startIndex + 2] = (byte)vector.Z; {
bytes[startIndex + 3] = (byte)vector.W; Vector4 vector = this.ToVector4();
break; vector *= MaxBytes;
default: vector += Half;
throw new NotSupportedException(); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
}
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
/// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
} }
/// <inheritdoc /> /// <inheritdoc />

32
src/ImageSharp/Colors/PackedPixel/IPackedBytes.cs

@ -12,7 +12,7 @@ namespace ImageSharp
public interface IPackedBytes public interface IPackedBytes
{ {
/// <summary> /// <summary>
/// Gets the packed representation from the gives bytes. /// Sets the packed representation from the given byte array.
/// </summary> /// </summary>
/// <param name="x">The x-component.</param> /// <param name="x">The x-component.</param>
/// <param name="y">The y-component.</param> /// <param name="y">The y-component.</param>
@ -21,11 +21,35 @@ namespace ImageSharp
void PackFromBytes(byte x, byte y, byte z, byte w); void PackFromBytes(byte x, byte y, byte z, byte w);
/// <summary> /// <summary>
/// Sets the packed representation into the gives bytes. /// Expands the packed representation into a given byte array.
/// Output is expanded to X-> Y-> Z order. Equivalent to R-> G-> B in <see cref="Color"/>
/// </summary> /// </summary>
/// <param name="bytes">The bytes to set the color in.</param> /// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param> /// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
/// <param name="componentOrder">The order of the components.</param> void ToXyzBytes(byte[] bytes, int startIndex);
void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder);
/// <summary>
/// Expands the packed representation into a given byte array.
/// Output is expanded to X-> Y-> Z-> W order. Equivalent to R-> G-> B-> A in <see cref="Color"/>
/// </summary>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
void ToXyzwBytes(byte[] bytes, int startIndex);
/// <summary>
/// Expands the packed representation into a given byte array.
/// Output is expanded to Z-> Y-> X order. Equivalent to B-> G-> R in <see cref="Color"/>
/// </summary>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
void ToZyxBytes(byte[] bytes, int startIndex);
/// <summary>
/// Expands the packed representation into a given byte array.
/// Output is expanded to Z-> Y-> X-> W order. Equivalent to B-> G-> R-> A in <see cref="Color"/>
/// </summary>
/// <param name="bytes">The bytes to set the color in.</param>
/// <param name="startIndex">The starting index of the <paramref name="bytes"/>.</param>
void ToZyxwBytes(byte[] bytes, int startIndex);
} }
} }

79
src/ImageSharp/Colors/PackedPixel/NormalizedByte2.cs

@ -120,7 +120,7 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4(); Vector4 vector = this.ToVector4();
vector *= Half; vector *= Half;
@ -129,33 +129,56 @@ namespace ImageSharp
vector += Round; vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
switch (componentOrder) bytes[startIndex] = (byte)vector.X;
{ bytes[startIndex + 1] = (byte)vector.Y;
case ComponentOrder.ZYX: bytes[startIndex + 2] = 0;
bytes[startIndex] = 0; }
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X; /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = 0; Vector4 vector = this.ToVector4();
bytes[startIndex + 1] = (byte)vector.Y; vector *= Half;
bytes[startIndex + 2] = (byte)vector.X; vector += Round;
bytes[startIndex + 3] = 255; vector += Half;
break; vector += Round;
case ComponentOrder.XYZ: vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y; bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 2] = 0; bytes[startIndex + 1] = (byte)vector.Y;
break; bytes[startIndex + 2] = 0;
case ComponentOrder.XYZW: bytes[startIndex + 3] = 255;
bytes[startIndex] = (byte)vector.X; }
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = 0; /// <inheritdoc />
bytes[startIndex + 3] = 255; public void ToZyxBytes(byte[] bytes, int startIndex)
break; {
default: Vector4 vector = this.ToVector4();
throw new NotSupportedException(); vector *= Half;
} vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = 0;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
/// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = 0;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = 255;
} }
/// <inheritdoc /> /// <inheritdoc />

79
src/ImageSharp/Colors/PackedPixel/NormalizedByte4.cs

@ -114,7 +114,7 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4(); Vector4 vector = this.ToVector4();
vector *= Half; vector *= Half;
@ -123,33 +123,56 @@ namespace ImageSharp
vector += Round; vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
switch (componentOrder) bytes[startIndex] = (byte)vector.X;
{ bytes[startIndex + 1] = (byte)vector.Y;
case ComponentOrder.ZYX: bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex] = (byte)vector.Z; }
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X; /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = (byte)vector.Z; Vector4 vector = this.ToVector4();
bytes[startIndex + 1] = (byte)vector.Y; vector *= Half;
bytes[startIndex + 2] = (byte)vector.X; vector += Round;
bytes[startIndex + 3] = (byte)vector.W; vector += Half;
break; vector += Round;
case ComponentOrder.XYZ: vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 1] = (byte)vector.Y; bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 2] = (byte)vector.Z; bytes[startIndex + 1] = (byte)vector.Y;
break; bytes[startIndex + 2] = (byte)vector.Z;
case ComponentOrder.XYZW: bytes[startIndex + 3] = (byte)vector.W;
bytes[startIndex] = (byte)vector.X; }
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z; /// <inheritdoc />
bytes[startIndex + 3] = (byte)vector.W; public void ToZyxBytes(byte[] bytes, int startIndex)
break; {
default: Vector4 vector = this.ToVector4();
throw new NotSupportedException(); vector *= Half;
} vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
}
/// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
} }
/// <inheritdoc /> /// <inheritdoc />

79
src/ImageSharp/Colors/PackedPixel/NormalizedShort2.cs

@ -108,7 +108,7 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4(); Vector4 vector = this.ToVector4();
vector *= Half; vector *= Half;
@ -117,33 +117,56 @@ namespace ImageSharp
vector += Round; vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
switch (componentOrder) bytes[startIndex] = (byte)(float)Math.Round(vector.X);
{ bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
case ComponentOrder.ZYX: bytes[startIndex + 2] = 0;
bytes[startIndex] = 0; }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = 0; Vector4 vector = this.ToVector4();
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); vector *= Half;
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); vector += Round;
bytes[startIndex + 3] = 255; vector += Half;
break; vector += Round;
case ComponentOrder.XYZ: vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 2] = 0; bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
break; bytes[startIndex + 2] = 0;
case ComponentOrder.XYZW: bytes[startIndex + 3] = 255;
bytes[startIndex] = (byte)(float)Math.Round(vector.X); }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = 0; /// <inheritdoc />
bytes[startIndex + 3] = 255; public void ToZyxBytes(byte[] bytes, int startIndex)
break; {
default: Vector4 vector = this.ToVector4();
throw new NotSupportedException(); vector *= Half;
} vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = 0;
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
}
/// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = 0;
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = 255;
} }
/// <summary> /// <summary>

79
src/ImageSharp/Colors/PackedPixel/NormalizedShort4.cs

@ -116,7 +116,7 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4(); Vector4 vector = this.ToVector4();
vector *= Half; vector *= Half;
@ -125,33 +125,56 @@ namespace ImageSharp
vector += Round; vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
switch (componentOrder) bytes[startIndex] = (byte)(float)Math.Round(vector.X);
{ bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
case ComponentOrder.ZYX: bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); Vector4 vector = this.ToVector4();
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); vector *= Half;
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); vector += Round;
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); vector += Half;
break; vector += Round;
case ComponentOrder.XYZ: vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
break; bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
case ComponentOrder.XYZW: bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
bytes[startIndex] = (byte)(float)Math.Round(vector.X); }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); /// <inheritdoc />
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); public void ToZyxBytes(byte[] bytes, int startIndex)
break; {
default: Vector4 vector = this.ToVector4();
throw new NotSupportedException(); vector *= Half;
} vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
}
/// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
} }
/// <inheritdoc /> /// <inheritdoc />

64
src/ImageSharp/Colors/PackedPixel/Rg32.cs

@ -100,37 +100,45 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4() * 255F; Vector4 vector = this.ToVector4() * 255F;
switch (componentOrder) bytes[startIndex] = (byte)vector.X;
{ bytes[startIndex + 1] = (byte)vector.Y;
case ComponentOrder.ZYX: bytes[startIndex + 2] = (byte)vector.Z;
bytes[startIndex] = (byte)vector.Z; }
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X; /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = (byte)vector.Z; Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X; bytes[startIndex] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W; bytes[startIndex + 1] = (byte)vector.Y;
break; bytes[startIndex + 2] = (byte)vector.Z;
case ComponentOrder.XYZ: bytes[startIndex + 3] = (byte)vector.W;
bytes[startIndex] = (byte)vector.X; }
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z; /// <inheritdoc />
break; public void ToZyxBytes(byte[] bytes, int startIndex)
case ComponentOrder.XYZW: {
bytes[startIndex] = (byte)vector.X; Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.Z; bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 3] = (byte)vector.W; bytes[startIndex + 1] = (byte)vector.Y;
break; bytes[startIndex + 2] = (byte)vector.X;
default: }
throw new NotSupportedException();
} /// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)vector.Z;
bytes[startIndex + 1] = (byte)vector.Y;
bytes[startIndex + 2] = (byte)vector.X;
bytes[startIndex + 3] = (byte)vector.W;
} }
/// <inheritdoc /> /// <inheritdoc />

64
src/ImageSharp/Colors/PackedPixel/Rgba1010102.cs

@ -95,37 +95,45 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4() * 255F; Vector4 vector = this.ToVector4() * 255F;
switch (componentOrder) bytes[startIndex] = (byte)(float)Math.Round(vector.X);
{ bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
case ComponentOrder.ZYX: bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
break; bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
case ComponentOrder.XYZ: bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
bytes[startIndex] = (byte)(float)Math.Round(vector.X); }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); /// <inheritdoc />
break; public void ToZyxBytes(byte[] bytes, int startIndex)
case ComponentOrder.XYZW: {
bytes[startIndex] = (byte)(float)Math.Round(vector.X); Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
break; bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
default: }
throw new NotSupportedException();
} /// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
} }
/// <inheritdoc /> /// <inheritdoc />

64
src/ImageSharp/Colors/PackedPixel/Rgba64.cs

@ -94,37 +94,45 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4() * 255F; Vector4 vector = this.ToVector4() * 255F;
switch (componentOrder) bytes[startIndex] = (byte)(float)Math.Round(vector.X);
{ bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
case ComponentOrder.ZYX: bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = (byte)(float)Math.Round(vector.Z); Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
break; bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
case ComponentOrder.XYZ: bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
bytes[startIndex] = (byte)(float)Math.Round(vector.X); }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); /// <inheritdoc />
break; public void ToZyxBytes(byte[] bytes, int startIndex)
case ComponentOrder.XYZW: {
bytes[startIndex] = (byte)(float)Math.Round(vector.X); Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z); bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W); bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
break; bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
default: }
throw new NotSupportedException();
} /// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4() * 255F;
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
} }
/// <inheritdoc /> /// <inheritdoc />

79
src/ImageSharp/Colors/PackedPixel/Short2.cs

@ -106,7 +106,7 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector2 vector = this.ToVector2(); Vector2 vector = this.ToVector2();
vector /= 65534; vector /= 65534;
@ -115,33 +115,56 @@ namespace ImageSharp
vector += Round; vector += Round;
vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes); vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes);
switch (componentOrder) bytes[startIndex] = (byte)(float)Math.Round(vector.X);
{ bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
case ComponentOrder.ZYX: bytes[startIndex + 2] = 0;
bytes[startIndex] = 0; }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); /// <inheritdoc />
break; public void ToXyzwBytes(byte[] bytes, int startIndex)
case ComponentOrder.ZYXW: {
bytes[startIndex] = 0; Vector2 vector = this.ToVector2();
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); vector /= 65534;
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X); vector *= 255;
bytes[startIndex + 3] = 255; vector += Half;
break; vector += Round;
case ComponentOrder.XYZ: vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes);
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y); bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 2] = 0; bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
break; bytes[startIndex + 2] = 0;
case ComponentOrder.XYZW: bytes[startIndex + 3] = 255;
bytes[startIndex] = (byte)(float)Math.Round(vector.X); }
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = 0; /// <inheritdoc />
bytes[startIndex + 3] = 255; public void ToZyxBytes(byte[] bytes, int startIndex)
break; {
default: Vector2 vector = this.ToVector2();
throw new NotSupportedException(); vector /= 65534;
} vector *= 255;
vector += Half;
vector += Round;
vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes);
bytes[startIndex] = 0;
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
}
/// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector2 vector = this.ToVector2();
vector /= 65534;
vector *= 255;
vector += Half;
vector += Round;
vector = Vector2.Clamp(vector, Vector2.Zero, MaxBytes);
bytes[startIndex] = 0;
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = 255;
} }
/// <summary> /// <summary>

91
src/ImageSharp/Colors/PackedPixel/Short4.cs

@ -112,7 +112,7 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
public void ToBytes(byte[] bytes, int startIndex, ComponentOrder componentOrder) public void ToXyzBytes(byte[] bytes, int startIndex)
{ {
Vector4 vector = this.ToVector4(); Vector4 vector = this.ToVector4();
vector /= 65534; vector /= 65534;
@ -121,50 +121,65 @@ namespace ImageSharp
vector += Round; vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes); vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
switch (componentOrder) bytes[startIndex] = (byte)(float)Math.Round(vector.X);
{ bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
case ComponentOrder.ZYX: bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
break;
case ComponentOrder.ZYXW:
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
break;
case ComponentOrder.XYZ:
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
break;
case ComponentOrder.XYZW:
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
break;
default:
throw new NotSupportedException();
}
} }
/// <summary> /// <inheritdoc />
/// Returns a value that indicates whether the current instance is equal to a specified object. public void ToXyzwBytes(byte[] bytes, int startIndex)
/// </summary> {
/// <param name="obj">The object with which to make the comparison.</param> Vector4 vector = this.ToVector4();
/// <returns>true if the current instance is equal to the specified object; false otherwise.</returns> vector /= 65534;
vector *= 255;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
}
/// <inheritdoc />
public void ToZyxBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector /= 65534;
vector *= 255;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
}
/// <inheritdoc />
public void ToZyxwBytes(byte[] bytes, int startIndex)
{
Vector4 vector = this.ToVector4();
vector /= 65534;
vector *= 255;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
bytes[startIndex] = (byte)(float)Math.Round(vector.Z);
bytes[startIndex + 1] = (byte)(float)Math.Round(vector.Y);
bytes[startIndex + 2] = (byte)(float)Math.Round(vector.X);
bytes[startIndex + 3] = (byte)(float)Math.Round(vector.W);
}
/// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj)
{ {
return (obj is Short4) && this == (Short4)obj; return (obj is Short4) && this == (Short4)obj;
} }
/// <summary> /// <inheritdoc />
/// Returns a value that indicates whether the current instance is equal to a specified object.
/// </summary>
/// <param name="other">The object with which to make the comparison.</param>
/// <returns>true if the current instance is equal to the specified object; false otherwise.</returns>
public bool Equals(Short4 other) public bool Equals(Short4 other)
{ {
return this == other; return this == other;

17
src/ImageSharp/Colors/Colorspaces/Bgra32.cs → src/ImageSharp/Colors/Spaces/Bgra32.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp namespace ImageSharp.Colors.Spaces
{ {
using System; using System;
using System.ComponentModel; using System.ComponentModel;
@ -22,7 +22,7 @@ namespace ImageSharp
/// <summary> /// <summary>
/// The backing vector for SIMD support. /// The backing vector for SIMD support.
/// </summary> /// </summary>
private Vector4 backingVector; private readonly Vector4 backingVector;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Bgra32"/> struct. /// Initializes a new instance of the <see cref="Bgra32"/> struct.
@ -133,7 +133,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
return GetHashCode(this); return this.backingVector.GetHashCode();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -152,16 +152,5 @@ namespace ImageSharp
{ {
return this.backingVector.Equals(other.backingVector); return this.backingVector.Equals(other.backingVector);
} }
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Bgra32"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private static int GetHashCode(Bgra32 color) => color.backingVector.GetHashCode();
} }
} }

24
src/ImageSharp/Colors/Colorspaces/CieLab.cs → src/ImageSharp/Colors/Spaces/CieLab.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp namespace ImageSharp.Colors.Spaces
{ {
using System; using System;
using System.ComponentModel; using System.ComponentModel;
@ -20,15 +20,10 @@ namespace ImageSharp
/// </summary> /// </summary>
public static readonly CieLab Empty = default(CieLab); public static readonly CieLab Empty = default(CieLab);
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.001f;
/// <summary> /// <summary>
/// The backing vector for SIMD support. /// The backing vector for SIMD support.
/// </summary> /// </summary>
private Vector3 backingVector; private readonly Vector3 backingVector;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CieLab"/> struct. /// Initializes a new instance of the <see cref="CieLab"/> struct.
@ -138,7 +133,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
return GetHashCode(this); return this.backingVector.GetHashCode();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -166,7 +161,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(CieLab other) public bool Equals(CieLab other)
{ {
return this.AlmostEquals(other, Epsilon); return this.AlmostEquals(other, Constants.Epsilon);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -178,16 +173,5 @@ namespace ImageSharp
&& result.Y < precision && result.Y < precision
&& result.Z < precision; && result.Z < precision;
} }
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="CieLab"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private static int GetHashCode(CieLab color) => color.backingVector.GetHashCode();
} }
} }

24
src/ImageSharp/Colors/Colorspaces/CieXyz.cs → src/ImageSharp/Colors/Spaces/CieXyz.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp namespace ImageSharp.Colors.Spaces
{ {
using System; using System;
using System.ComponentModel; using System.ComponentModel;
@ -20,15 +20,10 @@ namespace ImageSharp
/// </summary> /// </summary>
public static readonly CieXyz Empty = default(CieXyz); public static readonly CieXyz Empty = default(CieXyz);
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.001f;
/// <summary> /// <summary>
/// The backing vector for SIMD support. /// The backing vector for SIMD support.
/// </summary> /// </summary>
private Vector3 backingVector; private readonly Vector3 backingVector;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="CieXyz"/> struct. /// Initializes a new instance of the <see cref="CieXyz"/> struct.
@ -129,7 +124,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
return GetHashCode(this); return this.backingVector.GetHashCode();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -157,7 +152,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(CieXyz other) public bool Equals(CieXyz other)
{ {
return this.AlmostEquals(other, Epsilon); return this.AlmostEquals(other, Constants.Epsilon);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -169,16 +164,5 @@ namespace ImageSharp
&& result.Y < precision && result.Y < precision
&& result.Z < precision; && result.Z < precision;
} }
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Hsv"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private static int GetHashCode(CieXyz color) => color.backingVector.GetHashCode();
} }
} }

26
src/ImageSharp/Colors/Colorspaces/Cmyk.cs → src/ImageSharp/Colors/Spaces/Cmyk.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp namespace ImageSharp.Colors.Spaces
{ {
using System; using System;
using System.ComponentModel; using System.ComponentModel;
@ -19,15 +19,10 @@ namespace ImageSharp
/// </summary> /// </summary>
public static readonly Cmyk Empty = default(Cmyk); public static readonly Cmyk Empty = default(Cmyk);
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.001f;
/// <summary> /// <summary>
/// The backing vector for SIMD support. /// The backing vector for SIMD support.
/// </summary> /// </summary>
private Vector4 backingVector; private readonly Vector4 backingVector;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Cmyk"/> struct. /// Initializes a new instance of the <see cref="Cmyk"/> struct.
@ -90,7 +85,7 @@ namespace ImageSharp
float k = Math.Min(c, Math.Min(m, y)); float k = Math.Min(c, Math.Min(m, y));
if (Math.Abs(k - 1.0f) <= Epsilon) if (Math.Abs(k - 1.0f) <= Constants.Epsilon)
{ {
return new Cmyk(0, 0, 0, 1); return new Cmyk(0, 0, 0, 1);
} }
@ -139,7 +134,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
return GetHashCode(this); return this.backingVector.GetHashCode();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -167,7 +162,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(Cmyk other) public bool Equals(Cmyk other)
{ {
return this.AlmostEquals(other, Epsilon); return this.AlmostEquals(other, Constants.Epsilon);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -180,16 +175,5 @@ namespace ImageSharp
&& result.Z < precision && result.Z < precision
&& result.W < precision; && result.W < precision;
} }
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Cmyk"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private static int GetHashCode(Cmyk color) => color.backingVector.GetHashCode();
} }
} }

32
src/ImageSharp/Colors/Colorspaces/Hsl.cs → src/ImageSharp/Colors/Spaces/Hsl.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp namespace ImageSharp.Colors.Spaces
{ {
using System; using System;
using System.ComponentModel; using System.ComponentModel;
@ -19,15 +19,10 @@ namespace ImageSharp
/// </summary> /// </summary>
public static readonly Hsl Empty = default(Hsl); public static readonly Hsl Empty = default(Hsl);
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.001F;
/// <summary> /// <summary>
/// The backing vector for SIMD support. /// The backing vector for SIMD support.
/// </summary> /// </summary>
private Vector3 backingVector; private readonly Vector3 backingVector;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Hsl"/> struct. /// Initializes a new instance of the <see cref="Hsl"/> struct.
@ -85,20 +80,20 @@ namespace ImageSharp
float s = 0; float s = 0;
float l = (max + min) / 2; float l = (max + min) / 2;
if (Math.Abs(chroma) < Epsilon) if (Math.Abs(chroma) < Constants.Epsilon)
{ {
return new Hsl(0, s, l); return new Hsl(0, s, l);
} }
if (Math.Abs(r - max) < Epsilon) if (Math.Abs(r - max) < Constants.Epsilon)
{ {
h = (g - b) / chroma; h = (g - b) / chroma;
} }
else if (Math.Abs(g - max) < Epsilon) else if (Math.Abs(g - max) < Constants.Epsilon)
{ {
h = 2 + ((b - r) / chroma); h = 2 + ((b - r) / chroma);
} }
else if (Math.Abs(b - max) < Epsilon) else if (Math.Abs(b - max) < Constants.Epsilon)
{ {
h = 4 + ((r - g) / chroma); h = 4 + ((r - g) / chroma);
} }
@ -158,7 +153,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
return GetHashCode(this); return this.backingVector.GetHashCode();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -186,7 +181,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(Hsl other) public bool Equals(Hsl other)
{ {
return this.AlmostEquals(other, Epsilon); return this.AlmostEquals(other, Constants.Epsilon);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -198,16 +193,5 @@ namespace ImageSharp
&& result.Y < precision && result.Y < precision
&& result.Z < precision; && result.Z < precision;
} }
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Hsl"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private static int GetHashCode(Hsl color) => color.backingVector.GetHashCode();
} }
} }

32
src/ImageSharp/Colors/Colorspaces/Hsv.cs → src/ImageSharp/Colors/Spaces/Hsv.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp namespace ImageSharp.Colors.Spaces
{ {
using System; using System;
using System.ComponentModel; using System.ComponentModel;
@ -19,15 +19,10 @@ namespace ImageSharp
/// </summary> /// </summary>
public static readonly Hsv Empty = default(Hsv); public static readonly Hsv Empty = default(Hsv);
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.001F;
/// <summary> /// <summary>
/// The backing vector for SIMD support. /// The backing vector for SIMD support.
/// </summary> /// </summary>
private Vector3 backingVector; private readonly Vector3 backingVector;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Hsv"/> struct. /// Initializes a new instance of the <see cref="Hsv"/> struct.
@ -85,20 +80,20 @@ namespace ImageSharp
float s = 0; float s = 0;
float v = max; float v = max;
if (Math.Abs(chroma) < Epsilon) if (Math.Abs(chroma) < Constants.Epsilon)
{ {
return new Hsv(0, s, v); return new Hsv(0, s, v);
} }
if (Math.Abs(r - max) < Epsilon) if (Math.Abs(r - max) < Constants.Epsilon)
{ {
h = (g - b) / chroma; h = (g - b) / chroma;
} }
else if (Math.Abs(g - max) < Epsilon) else if (Math.Abs(g - max) < Constants.Epsilon)
{ {
h = 2 + ((b - r) / chroma); h = 2 + ((b - r) / chroma);
} }
else if (Math.Abs(b - max) < Epsilon) else if (Math.Abs(b - max) < Constants.Epsilon)
{ {
h = 4 + ((r - g) / chroma); h = 4 + ((r - g) / chroma);
} }
@ -151,7 +146,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
return GetHashCode(this); return this.backingVector.GetHashCode();
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -179,7 +174,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(Hsv other) public bool Equals(Hsv other)
{ {
return this.AlmostEquals(other, Epsilon); return this.AlmostEquals(other, Constants.Epsilon);
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -191,16 +186,5 @@ namespace ImageSharp
&& result.Y < precision && result.Y < precision
&& result.Z < precision; && result.Z < precision;
} }
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <param name="color">
/// The instance of <see cref="Hsv"/> to return the hash code for.
/// </param>
/// <returns>
/// A 32-bit signed integer that is the hash code for this instance.
/// </returns>
private static int GetHashCode(Hsv color) => color.backingVector.GetHashCode();
} }
} }

2
src/ImageSharp/Colors/Colorspaces/IAlmostEquatable.cs → src/ImageSharp/Colors/Spaces/IAlmostEquatable.cs

@ -3,7 +3,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp namespace ImageSharp.Colors.Spaces
{ {
using System; using System;

33
src/ImageSharp/Colors/Colorspaces/YCbCr.cs → src/ImageSharp/Colors/Spaces/YCbCr.cs

@ -3,10 +3,11 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp namespace ImageSharp.Colors.Spaces
{ {
using System; using System;
using System.ComponentModel; using System.ComponentModel;
using System.Numerics;
/// <summary> /// <summary>
/// Represents an YCbCr (luminance, blue chroma, red chroma) color conforming to the full range standard used in digital imaging systems. /// Represents an YCbCr (luminance, blue chroma, red chroma) color conforming to the full range standard used in digital imaging systems.
@ -19,6 +20,16 @@ namespace ImageSharp
/// </summary> /// </summary>
public static readonly YCbCr Empty = default(YCbCr); public static readonly YCbCr Empty = default(YCbCr);
/// <summary>
/// Vector which is used in clamping to the max value
/// </summary>
private static readonly Vector3 VectorMax = new Vector3(255);
/// <summary>
/// The backing vector for SIMD support.
/// </summary>
private readonly Vector3 backingVector;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="YCbCr"/> struct. /// Initializes a new instance of the <see cref="YCbCr"/> struct.
/// </summary> /// </summary>
@ -28,28 +39,26 @@ namespace ImageSharp
public YCbCr(byte y, byte cb, byte cr) public YCbCr(byte y, byte cb, byte cr)
: this() : this()
{ {
this.Y = y; this.backingVector = Vector3.Clamp(new Vector3(y, cb, cr), Vector3.Zero, VectorMax);
this.Cb = cb;
this.Cr = cr;
} }
/// <summary> /// <summary>
/// Gets the Y luminance component. /// Gets the Y luminance component.
/// <remarks>A value ranging between 0 and 255.</remarks> /// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary> /// </summary>
public byte Y { get; } public float Y => this.backingVector.X;
/// <summary> /// <summary>
/// Gets the Cb chroma component. /// Gets the Cb chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks> /// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary> /// </summary>
public byte Cb { get; } public float Cb => this.backingVector.Y;
/// <summary> /// <summary>
/// Gets the Cr chroma component. /// Gets the Cr chroma component.
/// <remarks>A value ranging between 0 and 255.</remarks> /// <remarks>A value ranging between 0 and 255.</remarks>
/// </summary> /// </summary>
public byte Cr { get; } public float Cr => this.backingVector.Z;
/// <summary> /// <summary>
/// Gets a value indicating whether this <see cref="YCbCr"/> is empty. /// Gets a value indicating whether this <see cref="YCbCr"/> is empty.
@ -117,13 +126,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode()
{ {
unchecked return this.backingVector.GetHashCode();
{
int hashCode = this.Y.GetHashCode();
hashCode = (hashCode * 397) ^ this.Cb.GetHashCode();
hashCode = (hashCode * 397) ^ this.Cr.GetHashCode();
return hashCode;
}
} }
/// <inheritdoc/> /// <inheritdoc/>
@ -151,7 +154,7 @@ namespace ImageSharp
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(YCbCr other) public bool Equals(YCbCr other)
{ {
return this.Y == other.Y && this.Cb == other.Cb && this.Cr == other.Cr; return this.backingVector.Equals(other.backingVector);
} }
} }
} }

13
src/ImageSharp/Colors/Vector4BlendTransforms.cs

@ -14,11 +14,6 @@ namespace ImageSharp
/// </summary> /// </summary>
public class Vector4BlendTransforms public class Vector4BlendTransforms
{ {
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.0001F;
/// <summary> /// <summary>
/// The blending formula simply selects the source vector. /// The blending formula simply selects the source vector.
/// </summary> /// </summary>
@ -203,13 +198,13 @@ namespace ImageSharp
amount = amount.Clamp(0, 1); amount = amount.Clamp(0, 1);
// Santize on zero alpha // Santize on zero alpha
if (Math.Abs(backdrop.W) < Epsilon) if (Math.Abs(backdrop.W) < Constants.Epsilon)
{ {
source.W *= amount; source.W *= amount;
return source; return source;
} }
if (Math.Abs(source.W) < Epsilon) if (Math.Abs(source.W) < Constants.Epsilon)
{ {
return backdrop; return backdrop;
} }
@ -266,7 +261,7 @@ namespace ImageSharp
/// </returns> /// </returns>
private static float BlendDodge(float b, float s) private static float BlendDodge(float b, float s)
{ {
return Math.Abs(s - 1F) < Epsilon ? s : Math.Min(b / (1F - s), 1F); return Math.Abs(s - 1F) < Constants.Epsilon ? s : Math.Min(b / (1F - s), 1F);
} }
/// <summary> /// <summary>
@ -279,7 +274,7 @@ namespace ImageSharp
/// </returns> /// </returns>
private static float BlendBurn(float b, float s) private static float BlendBurn(float b, float s)
{ {
return Math.Abs(s) < Epsilon ? s : Math.Max(1F - ((1F - b) / s), 0F); return Math.Abs(s) < Constants.Epsilon ? s : Math.Max(1F - ((1F - b) / s), 0F);
} }
/// <summary> /// <summary>

18
src/ImageSharp/Common/Constants.cs

@ -0,0 +1,18 @@
// <copyright file="Constants.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp
{
/// <summary>
/// Common constants used throughout the project
/// </summary>
internal static class Constants
{
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
public static readonly float Epsilon = 0.001f;
}
}

17
src/ImageSharp/Common/Helpers/ImageMaths.cs

@ -91,9 +91,7 @@ namespace ImageSharp
/// </returns> /// </returns>
public static float SinC(float x) public static float SinC(float x)
{ {
const float Epsilon = .00001F; if (Math.Abs(x) > Constants.Epsilon)
if (Math.Abs(x) > Epsilon)
{ {
x *= (float)Math.PI; x *= (float)Math.PI;
return Clean((float)Math.Sin(x) / x); return Clean((float)Math.Sin(x) / x);
@ -166,7 +164,6 @@ namespace ImageSharp
public static Rectangle GetFilteredBoundingRectangle<TColor>(ImageBase<TColor> bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B) public static Rectangle GetFilteredBoundingRectangle<TColor>(ImageBase<TColor> bitmap, float componentValue, RgbaComponent channel = RgbaComponent.B)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
const float Epsilon = .00001f;
int width = bitmap.Width; int width = bitmap.Width;
int height = bitmap.Height; int height = bitmap.Height;
Point topLeft = default(Point); Point topLeft = default(Point);
@ -178,19 +175,19 @@ namespace ImageSharp
switch (channel) switch (channel)
{ {
case RgbaComponent.R: case RgbaComponent.R:
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().X - b) > Epsilon; delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().X - b) > Constants.Epsilon;
break; break;
case RgbaComponent.G: case RgbaComponent.G:
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Y - b) > Epsilon; delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Y - b) > Constants.Epsilon;
break; break;
case RgbaComponent.B: case RgbaComponent.B:
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Z - b) > Epsilon; delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().Z - b) > Constants.Epsilon;
break; break;
default: default:
delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().W - b) > Epsilon; delegateFunc = (pixels, x, y, b) => Math.Abs(pixels[x, y].ToVector4().W - b) > Constants.Epsilon;
break; break;
} }
@ -278,9 +275,7 @@ namespace ImageSharp
/// </returns>. /// </returns>.
private static float Clean(float x) private static float Clean(float x)
{ {
const float Epsilon = .00001F; if (Math.Abs(x) < Constants.Epsilon)
if (Math.Abs(x) < Epsilon)
{ {
return 0F; return 0F;
} }

4
src/ImageSharp/Drawing/Processors/DrawPathProcessor.cs

@ -9,7 +9,6 @@ namespace ImageSharp.Drawing.Processors
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using System.Threading.Tasks; using System.Threading.Tasks;
using ImageSharp.Processors; using ImageSharp.Processors;
using Paths; using Paths;
using Pens; using Pens;
@ -27,7 +26,6 @@ namespace ImageSharp.Drawing.Processors
{ {
private const float AntialiasFactor = 1f; private const float AntialiasFactor = 1f;
private const int PaddingFactor = 1; // needs to been the same or greater than AntialiasFactor private const int PaddingFactor = 1; // needs to been the same or greater than AntialiasFactor
private const float Epsilon = 0.001f;
private readonly IPen<TColor> pen; private readonly IPen<TColor> pen;
private readonly IPath[] paths; private readonly IPath[] paths;
@ -138,7 +136,7 @@ namespace ImageSharp.Drawing.Processors
var opacity = this.Opacity(color.DistanceFromElement); var opacity = this.Opacity(color.DistanceFromElement);
if (opacity > Epsilon) if (opacity > Constants.Epsilon)
{ {
int offsetColorX = x - minX; int offsetColorX = x - minX;

4
src/ImageSharp/Drawing/Processors/FillShapeProcessor.cs

@ -21,8 +21,6 @@ namespace ImageSharp.Drawing.Processors
public class FillShapeProcessor<TColor> : ImageFilteringProcessor<TColor> public class FillShapeProcessor<TColor> : ImageFilteringProcessor<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
private const float Epsilon = 0.001f;
private const float AntialiasFactor = 1f; private const float AntialiasFactor = 1f;
private const int DrawPadding = 1; private const int DrawPadding = 1;
private readonly IBrush<TColor> fillColor; private readonly IBrush<TColor> fillColor;
@ -95,7 +93,7 @@ namespace ImageSharp.Drawing.Processors
float dist = this.poly.Distance(currentPoint); float dist = this.poly.Distance(currentPoint);
float opacity = this.Opacity(dist); float opacity = this.Opacity(dist);
if (opacity > Epsilon) if (opacity > Constants.Epsilon)
{ {
Vector4 backgroundVector = sourcePixels[offsetX, offsetY].ToVector4(); Vector4 backgroundVector = sourcePixels[offsetX, offsetY].ToVector4();
Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4(); Vector4 sourceVector = applicator.GetColor(currentPoint).ToVector4();

7
src/ImageSharp/Filters/Processors/Effects/BackgroundColorProcessor.cs

@ -16,11 +16,6 @@ namespace ImageSharp.Processors
public class BackgroundColorProcessor<TColor> : ImageFilteringProcessor<TColor> public class BackgroundColorProcessor<TColor> : ImageFilteringProcessor<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 0.001f;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="BackgroundColorProcessor{TColor}"/> class. /// Initializes a new instance of the <see cref="BackgroundColorProcessor{TColor}"/> class.
/// </summary> /// </summary>
@ -82,7 +77,7 @@ namespace ImageSharp.Processors
color = Vector4BlendTransforms.PremultipliedLerp(backgroundColor, color, .5F); color = Vector4BlendTransforms.PremultipliedLerp(backgroundColor, color, .5F);
} }
if (Math.Abs(a) < Epsilon) if (Math.Abs(a) < Constants.Epsilon)
{ {
color = backgroundColor; color = backgroundColor;
} }

13
src/ImageSharp/Filters/Processors/Transforms/RotateProcessor.cs

@ -70,9 +70,7 @@ namespace ImageSharp.Processors
/// <inheritdoc/> /// <inheritdoc/>
protected override void BeforeApply(ImageBase<TColor> source, Rectangle sourceRectangle) protected override void BeforeApply(ImageBase<TColor> source, Rectangle sourceRectangle)
{ {
const float Epsilon = .0001F; if (Math.Abs(this.Angle) < Constants.Epsilon || Math.Abs(this.Angle - 90) < Constants.Epsilon || Math.Abs(this.Angle - 180) < Constants.Epsilon || Math.Abs(this.Angle - 270) < Constants.Epsilon)
if (Math.Abs(this.Angle) < Epsilon || Math.Abs(this.Angle - 90) < Epsilon || Math.Abs(this.Angle - 180) < Epsilon || Math.Abs(this.Angle - 270) < Epsilon)
{ {
return; return;
} }
@ -91,26 +89,25 @@ namespace ImageSharp.Processors
/// <returns>The <see cref="bool"/></returns> /// <returns>The <see cref="bool"/></returns>
private bool OptimizedApply(ImageBase<TColor> source) private bool OptimizedApply(ImageBase<TColor> source)
{ {
const float Epsilon = .0001F; if (Math.Abs(this.Angle) < Constants.Epsilon)
if (Math.Abs(this.Angle) < Epsilon)
{ {
// No need to do anything so return. // No need to do anything so return.
return true; return true;
} }
if (Math.Abs(this.Angle - 90) < Epsilon) if (Math.Abs(this.Angle - 90) < Constants.Epsilon)
{ {
this.Rotate90(source); this.Rotate90(source);
return true; return true;
} }
if (Math.Abs(this.Angle - 180) < Epsilon) if (Math.Abs(this.Angle - 180) < Constants.Epsilon)
{ {
this.Rotate180(source); this.Rotate180(source);
return true; return true;
} }
if (Math.Abs(this.Angle - 270) < Epsilon) if (Math.Abs(this.Angle - 270) < Constants.Epsilon)
{ {
this.Rotate270(source); this.Rotate270(source);
return true; return true;

6
src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs

@ -275,7 +275,7 @@ namespace ImageSharp.Formats
const int ComponentCount = 2; const int ComponentCount = 2;
TColor color = default(TColor); TColor color = default(TColor);
using (PixelArea<TColor> row = new PixelArea<TColor>(width, ComponentOrder.XYZ)) using (PixelArea<TColor> row = new PixelArea<TColor>(width, ComponentOrder.Xyz))
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -312,7 +312,7 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
int padding = CalculatePadding(width, 3); int padding = CalculatePadding(width, 3);
using (PixelArea<TColor> row = new PixelArea<TColor>(width, ComponentOrder.ZYX, padding)) using (PixelArea<TColor> row = new PixelArea<TColor>(width, ComponentOrder.Zyx, padding))
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
@ -336,7 +336,7 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
int padding = CalculatePadding(width, 4); int padding = CalculatePadding(width, 4);
using (PixelArea<TColor> row = new PixelArea<TColor>(width, ComponentOrder.ZYXW, padding)) using (PixelArea<TColor> row = new PixelArea<TColor>(width, ComponentOrder.Zyxw, padding))
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {

8
src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs

@ -150,12 +150,12 @@ namespace ImageSharp.Formats
private void Write32Bit<TColor>(EndianBinaryWriter writer, PixelAccessor<TColor> pixels) private void Write32Bit<TColor>(EndianBinaryWriter writer, PixelAccessor<TColor> pixels)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
using (PixelArea<TColor> row = new PixelArea<TColor>(pixels.Width, ComponentOrder.ZYXW, this.padding)) using (PixelArea<TColor> row = new PixelArea<TColor>(pixels.Width, ComponentOrder.Zyxw, this.padding))
{ {
for (int y = pixels.Height - 1; y >= 0; y--) for (int y = pixels.Height - 1; y >= 0; y--)
{ {
pixels.CopyTo(row, y); pixels.CopyTo(row, y);
writer.Write(row.Bytes); writer.Write(row.Bytes, 0, row.Length);
} }
} }
} }
@ -169,12 +169,12 @@ namespace ImageSharp.Formats
private void Write24Bit<TColor>(EndianBinaryWriter writer, PixelAccessor<TColor> pixels) private void Write24Bit<TColor>(EndianBinaryWriter writer, PixelAccessor<TColor> pixels)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
using (PixelArea<TColor> row = new PixelArea<TColor>(pixels.Width, ComponentOrder.ZYX, this.padding)) using (PixelArea<TColor> row = new PixelArea<TColor>(pixels.Width, ComponentOrder.Zyx, this.padding))
{ {
for (int y = pixels.Height - 1; y >= 0; y--) for (int y = pixels.Height - 1; y >= 0; y--)
{ {
pixels.CopyTo(row, y); pixels.CopyTo(row, y);
writer.Write(row.Bytes); writer.Write(row.Bytes, 0, row.Length);
} }
} }
} }

2
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -451,7 +451,7 @@ namespace ImageSharp.Formats
} }
else else
{ {
using (PixelArea<TColor> emptyRow = new PixelArea<TColor>(this.restoreArea.Value.Width, ComponentOrder.XYZW)) using (PixelArea<TColor> emptyRow = new PixelArea<TColor>(this.restoreArea.Value.Width, ComponentOrder.Xyzw))
{ {
using (PixelAccessor<TColor> pixelAccessor = frame.Lock()) using (PixelAccessor<TColor> pixelAccessor = frame.Lock())
{ {

7
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -129,10 +129,10 @@ namespace ImageSharp.Formats
bool hasEmpty = false; bool hasEmpty = false;
// Some images may have more than one quantized pixel returned with an alpha value of zero // Some images may have more than one quantized pixel returned with an alpha value of zero
// (No idea why?!) so we should always ignore if we have empty pixels present. // so we should always ignore if we have empty pixels present.
for (int i = 0; i < quantized.Palette.Length; i++) for (int i = 0; i < quantized.Palette.Length; i++)
{ {
quantized.Palette[i].ToBytes(this.buffer, 0, ComponentOrder.XYZW); quantized.Palette[i].ToXyzwBytes(this.buffer, 0);
if (!hasEmpty) if (!hasEmpty)
{ {
@ -282,6 +282,7 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
writer.Write(GifConstants.ImageDescriptorLabel); // 2c writer.Write(GifConstants.ImageDescriptorLabel); // 2c
// TODO: Can we capture this? // TODO: Can we capture this?
writer.Write((ushort)0); // Left position writer.Write((ushort)0); // Left position
writer.Write((ushort)0); // Top position writer.Write((ushort)0); // Top position
@ -318,7 +319,7 @@ namespace ImageSharp.Formats
for (int i = 0; i < pixelCount; i++) for (int i = 0; i < pixelCount; i++)
{ {
int offset = i * 3; int offset = i * 3;
image.Palette[i].ToBytes(this.buffer, 0, ComponentOrder.XYZ); image.Palette[i].ToXyzBytes(this.buffer, 0);
colorTable[offset] = this.buffer[0]; colorTable[offset] = this.buffer[0];
colorTable[offset + 1] = this.buffer[1]; colorTable[offset + 1] = this.buffer[1];
colorTable[offset + 2] = this.buffer[2]; colorTable[offset + 2] = this.buffer[2];

18
src/ImageSharp/Formats/Jpg/Components/BlockQuad.cs

@ -0,0 +1,18 @@
// <copyright file="BlockQuad.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Formats.Jpg.Components
{
/// <summary>
/// Poor man's stackalloc: Contains a value-type <see cref="float"/> buffer sized for 4 <see cref="Block8x8F"/> instances.
/// Useful for decoder/encoder operations allocating a block for each Jpeg component.
/// </summary>
internal unsafe struct BlockQuad
{
/// <summary>
/// The value-type <see cref="float"/> buffer sized for 4 <see cref="Block8x8F"/> instances.
/// </summary>
public fixed float Data[4 * Block8x8F.ScalarCount];
}
}

4
src/ImageSharp/Formats/Jpg/Components/Decoder/Bits.cs

@ -47,7 +47,7 @@ namespace ImageSharp.Formats.Jpg
// Grab the decode bytes, use them and then set them // Grab the decode bytes, use them and then set them
// back on the decoder. // back on the decoder.
var decoderBytes = decoder.Bytes; Bytes decoderBytes = decoder.Bytes;
byte c = decoderBytes.ReadByteStuffedByte(decoder.InputStream, out errorCode); byte c = decoderBytes.ReadByteStuffedByte(decoder.InputStream, out errorCode);
decoder.Bytes = decoderBytes; decoder.Bytes = decoderBytes;
@ -84,7 +84,7 @@ namespace ImageSharp.Formats.Jpg
{ {
if (this.UnreadBits < t) if (this.UnreadBits < t)
{ {
var errorCode = this.EnsureNBits(t, decoder); JpegDecoderCore.ErrorCodes errorCode = this.EnsureNBits(t, decoder);
if (errorCode != JpegDecoderCore.ErrorCodes.NoError) if (errorCode != JpegDecoderCore.ErrorCodes.NoError)
{ {
throw new JpegDecoderCore.MissingFF00Exception(); throw new JpegDecoderCore.MissingFF00Exception();

287
src/ImageSharp/Formats/Jpg/JpegEncoderCore.cs

@ -2,6 +2,7 @@
// Copyright (c) James Jackson-South and contributors. // Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
// </copyright> // </copyright>
namespace ImageSharp.Formats namespace ImageSharp.Formats
{ {
using System; using System;
@ -11,19 +12,20 @@ namespace ImageSharp.Formats
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using ImageSharp.Formats.Jpg; using ImageSharp.Formats.Jpg;
using ImageSharp.Formats.Jpg.Components;
/// <summary> /// <summary>
/// Image encoder for writing an image to a stream as a jpeg. /// Image encoder for writing an image to a stream as a jpeg.
/// </summary> /// </summary>
internal unsafe class JpegEncoderCore internal unsafe class JpegEncoderCore
{ {
/// <summary> /// <summary>
/// The number of quantization tables. /// The number of quantization tables.
/// </summary> /// </summary>
private const int QuantizationTableCount = 2; private const int QuantizationTableCount = 2;
/// <summary> /// <summary>
/// Counts the number of bits needed to hold an integer. /// Counts the number of bits needed to hold an integer.
/// </summary> /// </summary>
private static readonly uint[] BitCountLut = private static readonly uint[] BitCountLut =
{ {
@ -43,15 +45,15 @@ namespace ImageSharp.Formats
}; };
/// <summary> /// <summary>
/// The SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes: /// The SOS (Start Of Scan) marker "\xff\xda" followed by 12 bytes:
/// - the marker length "\x00\x0c", /// - the marker length "\x00\x0c",
/// - the number of components "\x03", /// - the number of components "\x03",
/// - component 1 uses DC table 0 and AC table 0 "\x01\x00", /// - component 1 uses DC table 0 and AC table 0 "\x01\x00",
/// - component 2 uses DC table 1 and AC table 1 "\x02\x11", /// - component 2 uses DC table 1 and AC table 1 "\x02\x11",
/// - component 3 uses DC table 1 and AC table 1 "\x03\x11", /// - component 3 uses DC table 1 and AC table 1 "\x03\x11",
/// - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for /// - the bytes "\x00\x3f\x00". Section B.2.3 of the spec says that for
/// sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al) /// sequential DCTs, those bytes (8-bit Ss, 8-bit Se, 4-bit Ah, 4-bit Al)
/// should be 0x00, 0x3f, 0x00&lt;&lt;4 | 0x00. /// should be 0x00, 0x3f, 0x00&lt;&lt;4 | 0x00.
/// </summary> /// </summary>
private static readonly byte[] SosHeaderYCbCr = private static readonly byte[] SosHeaderYCbCr =
{ {
@ -76,10 +78,10 @@ namespace ImageSharp.Formats
}; };
/// <summary> /// <summary>
/// The unscaled quantization tables in zig-zag order. Each /// The unscaled quantization tables in zig-zag order. Each
/// encoder copies and scales the tables according to its quality parameter. /// encoder copies and scales the tables according to its quality parameter.
/// The values are derived from section K.1 after converting from natural to /// The values are derived from section K.1 after converting from natural to
/// zig-zag order. /// zig-zag order.
/// </summary> /// </summary>
private static readonly byte[,] UnscaledQuant = private static readonly byte[,] UnscaledQuant =
{ {
@ -102,69 +104,59 @@ namespace ImageSharp.Formats
}; };
/// <summary> /// <summary>
/// A scratch buffer to reduce allocations. /// A scratch buffer to reduce allocations.
/// </summary> /// </summary>
private readonly byte[] buffer = new byte[16]; private readonly byte[] buffer = new byte[16];
/// <summary> /// <summary>
/// A buffer for reducing the number of stream writes when emitting Huffman tables. 64 seems to be enough. /// A buffer for reducing the number of stream writes when emitting Huffman tables. 64 seems to be enough.
/// </summary> /// </summary>
private readonly byte[] emitBuffer = new byte[64]; private readonly byte[] emitBuffer = new byte[64];
/// <summary> /// <summary>
/// A buffer for reducing the number of stream writes when emitting Huffman tables. Max combined table lengths + /// A buffer for reducing the number of stream writes when emitting Huffman tables. Max combined table lengths +
/// identifier. /// identifier.
/// </summary> /// </summary>
private readonly byte[] huffmanBuffer = new byte[179]; private readonly byte[] huffmanBuffer = new byte[179];
/// <summary> /// <summary>
/// The accumulated bits to write to the stream. /// The accumulated bits to write to the stream.
/// </summary> /// </summary>
private uint accumulatedBits; private uint accumulatedBits;
/// <summary> /// <summary>
/// The accumulated bit count. /// The accumulated bit count.
/// </summary> /// </summary>
private uint bitCount; private uint bitCount;
/// <summary> /// <summary>
/// The scaled chrominance table, in zig-zag order. /// The scaled chrominance table, in zig-zag order.
/// </summary> /// </summary>
private Block8x8F chrominanceQuantTable; private Block8x8F chrominanceQuantTable;
/// <summary> /// <summary>
/// The scaled luminance table, in zig-zag order. /// The scaled luminance table, in zig-zag order.
/// </summary> /// </summary>
private Block8x8F luminanceQuantTable; private Block8x8F luminanceQuantTable;
/// <summary> /// <summary>
/// The output stream. All attempted writes after the first error become no-ops. /// The output stream. All attempted writes after the first error become no-ops.
/// </summary> /// </summary>
private Stream outputStream; private Stream outputStream;
/// <summary> /// <summary>
/// The subsampling method to use. /// The subsampling method to use.
/// </summary> /// </summary>
private JpegSubsample subsample; private JpegSubsample subsample;
/// <summary> /// <summary>
/// Encode writes the image to the jpeg baseline format with the given options. /// Encode writes the image to the jpeg baseline format with the given options.
/// </summary> /// </summary>
/// <typeparam name="TColor"> /// <typeparam name="TColor">The pixel format.</typeparam>
/// The pixel format. /// <param name="image">The image to write from.</param>
/// </typeparam> /// <param name="stream">The stream to write to.</param>
/// <param name="image"> /// <param name="quality">The quality.</param>
/// The image to write from. /// <param name="sample">The subsampling mode.</param>
/// </param>
/// <param name="stream">
/// The stream to write to.
/// </param>
/// <param name="quality">
/// The quality.
/// </param>
/// <param name="sample">
/// The subsampling mode.
/// </param>
public void Encode<TColor>(Image<TColor> image, Stream stream, int quality, JpegSubsample sample) public void Encode<TColor>(Image<TColor> image, Stream stream, int quality, JpegSubsample sample)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
@ -235,6 +227,28 @@ namespace ImageSharp.Formats
stream.Flush(); stream.Flush();
} }
/// <summary>
/// Writes data to "Define Quantization Tables" block for QuantIndex
/// </summary>
/// <param name="dqt">The "Define Quantization Tables" block</param>
/// <param name="offset">Offset in "Define Quantization Tables" block</param>
/// <param name="i">The quantization index</param>
/// <param name="quant">The quantization table to copy data from</param>
private static void WriteDataToDqt(byte[] dqt, ref int offset, QuantIndex i, ref Block8x8F quant)
{
dqt[offset++] = (byte)i;
for (int j = 0; j < Block8x8F.ScalarCount; j++)
{
dqt[offset++] = (byte)quant[j];
}
}
/// <summary>
/// Initializes quantization table.
/// </summary>
/// <param name="i">The quantization index.</param>
/// <param name="scale">The scaling factor.</param>
/// <param name="quant">The quantization table.</param>
private static void InitQuantizationTable(int i, int scale, ref Block8x8F quant) private static void InitQuantizationTable(int i, int scale, ref Block8x8F quant)
{ {
for (int j = 0; j < Block8x8F.ScalarCount; j++) for (int j = 0; j < Block8x8F.ScalarCount; j++)
@ -258,30 +272,14 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Converts the 8x8 region of the image whose top-left corner is x,y to its YCbCr values. /// Converts the 8x8 region of the image whose top-left corner is x,y to its YCbCr values.
/// </summary> /// </summary>
/// <typeparam name="TColor"> /// <typeparam name="TColor">The pixel format.</typeparam>
/// The pixel format. /// <param name="pixels">The pixel accessor.</param>
/// </typeparam> /// <param name="x">The x-position within the image.</param>
/// <param name="pixels"> /// <param name="y">The y-position within the image.</param>
/// The pixel accessor. /// <param name="yBlock">The luminance block.</param>
/// </param> /// <param name="cbBlock">The red chroma block.</param>
/// <param name="x"> /// <param name="crBlock">The blue chroma block.</param>
/// The x-position within the image. /// <param name="rgbBytes">Temporal <see cref="PixelArea{TColor}"/> provided by the caller</param>
/// </param>
/// <param name="y">
/// The y-position within the image.
/// </param>
/// <param name="yBlock">
/// The luminance block.
/// </param>
/// <param name="cbBlock">
/// The red chroma block.
/// </param>
/// <param name="crBlock">
/// The blue chroma block.
/// </param>
/// <param name="rgbBytes">
/// Temporal <see cref="PixelArea{TColor}"/> provided by the caller
/// </param>
private static void ToYCbCr<TColor>( private static void ToYCbCr<TColor>(
PixelAccessor<TColor> pixels, PixelAccessor<TColor> pixels,
int x, int x,
@ -326,18 +324,14 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Emits the least significant count of bits of bits to the bit-stream. /// Emits the least significant count of bits of bits to the bit-stream.
/// The precondition is bits /// The precondition is bits
/// <example> /// <example>
/// &lt; 1&lt;&lt;nBits &amp;&amp; nBits &lt;= 16 /// &lt; 1&lt;&lt;nBits &amp;&amp; nBits &lt;= 16
/// </example> /// </example>
/// . /// .
/// </summary> /// </summary>
/// <param name="bits"> /// <param name="bits">The packed bits.</param>
/// The packed bits. /// <param name="count">The number of bits</param>
/// </param>
/// <param name="count">
/// The number of bits
/// </param>
private void Emit(uint bits, uint count) private void Emit(uint bits, uint count)
{ {
count += this.bitCount; count += this.bitCount;
@ -375,12 +369,8 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Emits the given value with the given Huffman encoder. /// Emits the given value with the given Huffman encoder.
/// </summary> /// </summary>
/// <param name="index"> /// <param name="index">The index of the Huffman encoder</param>
/// The index of the Huffman encoder /// <param name="value">The value to encode.</param>
/// </param>
/// <param name="value">
/// The value to encode.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EmitHuff(HuffIndex index, int value) private void EmitHuff(HuffIndex index, int value)
{ {
@ -391,15 +381,9 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Emits a run of runLength copies of value encoded with the given Huffman encoder. /// Emits a run of runLength copies of value encoded with the given Huffman encoder.
/// </summary> /// </summary>
/// <param name="index"> /// <param name="index">The index of the Huffman encoder</param>
/// The index of the Huffman encoder /// <param name="runLength">The number of copies to encode.</param>
/// </param> /// <param name="value">The value to encode.</param>
/// <param name="runLength">
/// The number of copies to encode.
/// </param>
/// <param name="value">
/// The value to encode.
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private void EmitHuffRLE(HuffIndex index, int runLength, int value) private void EmitHuffRLE(HuffIndex index, int runLength, int value)
{ {
@ -431,12 +415,8 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Encodes the image with no subsampling. /// Encodes the image with no subsampling.
/// </summary> /// </summary>
/// <typeparam name="TColor"> /// <typeparam name="TColor">The pixel format.</typeparam>
/// The pixel format. /// <param name="pixels">The pixel accessor providing access to the image pixels.</param>
/// </typeparam>
/// <param name="pixels">
/// The pixel accessor providing access to the image pixels.
/// </param>
private void Encode444<TColor>(PixelAccessor<TColor> pixels) private void Encode444<TColor>(PixelAccessor<TColor> pixels)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
@ -456,7 +436,7 @@ namespace ImageSharp.Formats
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
float prevDCY = 0, prevDCCb = 0, prevDCCr = 0; float prevDCY = 0, prevDCCb = 0, prevDCCr = 0;
using (PixelArea<TColor> rgbBytes = new PixelArea<TColor>(8, 8, ComponentOrder.XYZ, true)) using (PixelArea<TColor> rgbBytes = new PixelArea<TColor>(8, 8, ComponentOrder.Xyz))
{ {
for (int y = 0; y < pixels.Height; y += 8) for (int y = 0; y < pixels.Height; y += 8)
{ {
@ -496,12 +476,8 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Writes the application header containing the JFIF identifier plus extra data. /// Writes the application header containing the JFIF identifier plus extra data.
/// </summary> /// </summary>
/// <param name="horizontalResolution"> /// <param name="horizontalResolution">The resolution of the image in the x- direction.</param>
/// The resolution of the image in the x- direction. /// <param name="verticalResolution">The resolution of the image in the y- direction.</param>
/// </param>
/// <param name="verticalResolution">
/// The resolution of the image in the y- direction.
/// </param>
private void WriteApplicationHeader(short horizontalResolution, short verticalResolution) private void WriteApplicationHeader(short horizontalResolution, short verticalResolution)
{ {
// Write the start of image marker. Markers are always prefixed with with 0xff. // Write the start of image marker. Markers are always prefixed with with 0xff.
@ -539,30 +515,16 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Writes a block of pixel data using the given quantization table, /// Writes a block of pixel data using the given quantization table,
/// returning the post-quantized DC value of the DCT-transformed block. /// returning the post-quantized DC value of the DCT-transformed block.
/// The block is in natural (not zig-zag) order. /// The block is in natural (not zig-zag) order.
/// </summary> /// </summary>
/// <param name="index"> /// <param name="index">The quantization table index.</param>
/// The quantization table index. /// <param name="prevDC">The previous DC value.</param>
/// </param> /// <param name="src">Source block</param>
/// <param name="prevDC"> /// <param name="tempDest">Temporal block to be used as FDCT Destination</param>
/// The previous DC value. /// <param name="temp2">Temporal block 2</param>
/// </param> /// <param name="quant">Quantization table</param>
/// <param name="src"> /// <param name="unzigPtr">The 8x8 Unzig block pointer</param>
/// Source block
/// </param>
/// <param name="tempDest">
/// Temporal block to be used as FDCT Destination
/// </param>
/// <param name="temp2">
/// Temporal block 2
/// </param>
/// <param name="quant">
/// Quantization table
/// </param>
/// <param name="unzigPtr">
/// The 8x8 Unzig block ptr
/// </param>
/// <returns> /// <returns>
/// The <see cref="int"/> /// The <see cref="int"/>
/// </returns> /// </returns>
@ -622,9 +584,7 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Writes the Define Huffman Table marker and tables. /// Writes the Define Huffman Table marker and tables.
/// </summary> /// </summary>
/// <param name="componentCount"> /// <param name="componentCount">The number of components to write.</param>
/// The number of components to write.
/// </param>
private void WriteDefineHuffmanTables(int componentCount) private void WriteDefineHuffmanTables(int componentCount)
{ {
// Table identifiers. // Table identifiers.
@ -671,7 +631,7 @@ namespace ImageSharp.Formats
} }
/// <summary> /// <summary>
/// Writes the Define Quantization Marker and tables. /// Writes the Define Quantization Marker and tables.
/// </summary> /// </summary>
private void WriteDefineQuantizationTables() private void WriteDefineQuantizationTables()
{ {
@ -685,8 +645,8 @@ namespace ImageSharp.Formats
byte[] dqt = ArrayPool<byte>.Shared.Rent(dqtCount); byte[] dqt = ArrayPool<byte>.Shared.Rent(dqtCount);
int offset = 0; int offset = 0;
JpegUtils.WriteDataToDqt(dqt, ref offset, QuantIndex.Luminance, ref this.luminanceQuantTable); WriteDataToDqt(dqt, ref offset, QuantIndex.Luminance, ref this.luminanceQuantTable);
JpegUtils.WriteDataToDqt(dqt, ref offset, QuantIndex.Chrominance, ref this.chrominanceQuantTable); WriteDataToDqt(dqt, ref offset, QuantIndex.Chrominance, ref this.chrominanceQuantTable);
this.outputStream.Write(dqt, 0, dqtCount); this.outputStream.Write(dqt, 0, dqtCount);
ArrayPool<byte>.Shared.Return(dqt); ArrayPool<byte>.Shared.Return(dqt);
@ -695,9 +655,7 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Writes the EXIF profile. /// Writes the EXIF profile.
/// </summary> /// </summary>
/// <param name="exifProfile"> /// <param name="exifProfile">The exif profile.</param>
/// The exif profile.
/// </param>
/// <exception cref="ImageFormatException"> /// <exception cref="ImageFormatException">
/// Thrown if the EXIF profile size exceeds the limit /// Thrown if the EXIF profile size exceeds the limit
/// </exception> /// </exception>
@ -729,12 +687,8 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Writes the metadata profiles to the image. /// Writes the metadata profiles to the image.
/// </summary> /// </summary>
/// <param name="image"> /// <param name="image">The image.</param>
/// The image. /// <typeparam name="TColor">The pixel format.</typeparam>
/// </param>
/// <typeparam name="TColor">
/// The pixel format.
/// </typeparam>
private void WriteProfiles<TColor>(Image<TColor> image) private void WriteProfiles<TColor>(Image<TColor> image)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
@ -744,15 +698,9 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Writes the Start Of Frame (Baseline) marker /// Writes the Start Of Frame (Baseline) marker
/// </summary> /// </summary>
/// <param name="width"> /// <param name="width">The width of the image</param>
/// The width of the image /// <param name="height">The height of the image</param>
/// </param> /// <param name="componentCount">The number of components in a pixel</param>
/// <param name="height">
/// The height of the image
/// </param>
/// <param name="componentCount">
/// The number of components in a pixel
/// </param>
private void WriteStartOfFrame(int width, int height, int componentCount) private void WriteStartOfFrame(int width, int height, int componentCount)
{ {
// "default" to 4:2:0 // "default" to 4:2:0
@ -806,12 +754,8 @@ namespace ImageSharp.Formats
/// <summary> /// <summary>
/// Writes the StartOfScan marker. /// Writes the StartOfScan marker.
/// </summary> /// </summary>
/// <typeparam name="TColor"> /// <typeparam name="TColor">The pixel format.</typeparam>
/// The pixel format. /// <param name="pixels">The pixel accessor providing access to the image pixels.</param>
/// </typeparam>
/// <param name="pixels">
/// The pixel accessor providing access to the image pixels.
/// </param>
private void WriteStartOfScan<TColor>(PixelAccessor<TColor> pixels) private void WriteStartOfScan<TColor>(PixelAccessor<TColor> pixels)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
@ -833,28 +777,12 @@ namespace ImageSharp.Formats
this.Emit(0x7f, 7); this.Emit(0x7f, 7);
} }
#pragma warning disable SA1201 // MethodShouldNotFollowAStruct
/// <summary>
/// Poor man's stackalloc for Encode420.
/// This struct belongs to Encode420. Much easeier to understand code if they are close to each other. Why should I
/// move it Up? :P
/// </summary>
private struct BlockQuad
{
public fixed float Data[4 * Block8x8F.ScalarCount];
}
/// <summary> /// <summary>
/// Encodes the image with subsampling. The Cb and Cr components are each subsampled /// Encodes the image with subsampling. The Cb and Cr components are each subsampled
/// at a factor of 2 both horizontally and vertically. /// at a factor of 2 both horizontally and vertically.
/// </summary> /// </summary>
/// <typeparam name="TColor"> /// <typeparam name="TColor">The pixel format.</typeparam>
/// The pixel format. /// <param name="pixels">The pixel accessor providing access to the image pixels.</param>
/// </typeparam>
/// <param name="pixels">
/// The pixel accessor providing access to the image pixels.
/// </param>
private void Encode420<TColor>(PixelAccessor<TColor> pixels) private void Encode420<TColor>(PixelAccessor<TColor> pixels)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
@ -877,7 +805,7 @@ namespace ImageSharp.Formats
// ReSharper disable once InconsistentNaming // ReSharper disable once InconsistentNaming
float prevDCY = 0, prevDCCb = 0, prevDCCr = 0; float prevDCY = 0, prevDCCb = 0, prevDCCr = 0;
using (var rgbBytes = new PixelArea<TColor>(8, 8, ComponentOrder.XYZ, true)) using (PixelArea<TColor> rgbBytes = new PixelArea<TColor>(8, 8, ComponentOrder.Xyz))
{ {
for (int y = 0; y < pixels.Height; y += 16) for (int y = 0; y < pixels.Height; y += 16)
{ {
@ -909,6 +837,7 @@ namespace ImageSharp.Formats
&temp2, &temp2,
&onStackChrominanceQuantTable, &onStackChrominanceQuantTable,
unzig.Data); unzig.Data);
Block8x8F.Scale16X16To8X8(&b, crPtr); Block8x8F.Scale16X16To8X8(&b, crPtr);
prevDCCr = this.WriteBlock( prevDCCr = this.WriteBlock(
QuantIndex.Chrominance, QuantIndex.Chrominance,
@ -923,17 +852,11 @@ namespace ImageSharp.Formats
} }
} }
#pragma warning restore SA1201
/// <summary> /// <summary>
/// Writes the header for a marker with the given length. /// Writes the header for a marker with the given length.
/// </summary> /// </summary>
/// <param name="marker"> /// <param name="marker">The marker to write.</param>
/// The marker to write. /// <param name="length">The marker length.</param>
/// </param>
/// <param name="length">
/// The marker length.
/// </param>
private void WriteMarkerHeader(byte marker, int length) private void WriteMarkerHeader(byte marker, int length)
{ {
// Markers are always prefixed with with 0xff. // Markers are always prefixed with with 0xff.

70
src/ImageSharp/Formats/Jpg/Utils/JpegUtils.cs

@ -13,24 +13,13 @@ namespace ImageSharp.Formats.Jpg
internal static unsafe class JpegUtils internal static unsafe class JpegUtils
{ {
/// <summary> /// <summary>
/// Copy a region of an image into dest. De "outlier" area will be stretched out with pixels on the right and bottom of /// Copy a region of an image into dest. De "outlier" area will be stretched out with pixels on the right and bottom of the image.
/// the image.
/// </summary> /// </summary>
/// <typeparam name="TColor"> /// <typeparam name="TColor">The pixel type</typeparam>
/// The pixel type /// <param name="pixels">The input pixel acessor</param>
/// </typeparam> /// <param name="dest">The destination <see cref="PixelArea{TColor}"/></param>
/// <param name="pixels"> /// <param name="sourceY">Starting Y coord</param>
/// The input pixel acessor /// <param name="sourceX">Starting X coord</param>
/// </param>
/// <param name="dest">
/// The destination <see cref="PixelArea{TColor}"/>
/// </param>
/// <param name="sourceY">
/// Starting Y coord
/// </param>
/// <param name="sourceX">
/// Starting X coord
/// </param>
public static void CopyRGBBytesStretchedTo<TColor>( public static void CopyRGBBytesStretchedTo<TColor>(
this PixelAccessor<TColor> pixels, this PixelAccessor<TColor> pixels,
PixelArea<TColor> dest, PixelArea<TColor> dest,
@ -38,7 +27,7 @@ namespace ImageSharp.Formats.Jpg
int sourceX) int sourceX)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
pixels.CopyTo(dest, sourceY, sourceX); pixels.SafeCopyTo(dest, sourceY, sourceX);
int stretchFromX = pixels.Width - sourceX; int stretchFromX = pixels.Width - sourceX;
int stretchFromY = pixels.Height - sourceY; int stretchFromY = pixels.Height - sourceY;
StretchPixels(dest, stretchFromX, stretchFromY); StretchPixels(dest, stretchFromX, stretchFromY);
@ -47,46 +36,19 @@ namespace ImageSharp.Formats.Jpg
/// <summary> /// <summary>
/// Copy an RGB value /// Copy an RGB value
/// </summary> /// </summary>
/// <param name="source"> /// <param name="source">Source pointer</param>
/// Source pointer /// <param name="dest">Destination pointer</param>
/// </param>
/// <param name="dest">
/// Destination pointer
/// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static void CopyRgb(byte* source, byte* dest) public static void CopyRgb(byte* source, byte* dest)
{ {
*dest++ = *source++; // R *dest++ = *source++; // R
*dest++ = *source++; // G *dest++ = *source++; // G
*dest = *source; // B *dest = *source; // B
} }
/// <summary> // Nothing to stretch if (fromX, fromY) is outside the area, or is at (0,0)
/// Writes data to "Define Quantization Tables" block for QuantIndex
/// </summary>
/// <param name="dqt">
/// The "Define Quantization Tables" block
/// </param>
/// <param name="offset">
/// Offset in dqt
/// </param>
/// <param name="i">
/// The quantization index
/// </param>
/// <param name="q">
/// The quantazation table to copy data from
/// </param>
internal static void WriteDataToDqt(byte[] dqt, ref int offset, QuantIndex i, ref Block8x8F q)
{
dqt[offset++] = (byte)i;
for (int j = 0; j < Block8x8F.ScalarCount; j++)
{
dqt[offset++] = (byte)q[j];
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private static bool IsInvalidStretchArea<TColor>(PixelArea<TColor> area, int fromX, int fromY) private static bool IsInvalidStretchStartingPosition<TColor>(PixelArea<TColor> area, int fromX, int fromY)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
return fromX <= 0 || fromY <= 0 || fromX >= area.Width || fromY >= area.Height; return fromX <= 0 || fromY <= 0 || fromX >= area.Width || fromY >= area.Height;
@ -95,14 +57,14 @@ namespace ImageSharp.Formats.Jpg
private static void StretchPixels<TColor>(PixelArea<TColor> area, int fromX, int fromY) private static void StretchPixels<TColor>(PixelArea<TColor> area, int fromX, int fromY)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
if (IsInvalidStretchArea(area, fromX, fromY)) if (IsInvalidStretchStartingPosition(area, fromX, fromY))
{ {
return; return;
} }
for (int y = 0; y < fromY; y++) for (int y = 0; y < fromY; y++)
{ {
byte* ptrBase = (byte*)area.DataPointer + (y * area.RowByteCount); byte* ptrBase = (byte*)area.DataPointer + (y * area.RowStride);
for (int x = fromX; x < area.Width; x++) for (int x = fromX; x < area.Width; x++)
{ {
@ -115,8 +77,8 @@ namespace ImageSharp.Formats.Jpg
for (int y = fromY; y < area.Height; y++) for (int y = fromY; y < area.Height; y++)
{ {
byte* currBase = (byte*)area.DataPointer + (y * area.RowByteCount); byte* currBase = (byte*)area.DataPointer + (y * area.RowStride);
byte* prevBase = (byte*)area.DataPointer + ((y - 1) * area.RowByteCount); byte* prevBase = (byte*)area.DataPointer + ((y - 1) * area.RowStride);
for (int x = 0; x < area.Width; x++) for (int x = 0; x < area.Width; x++)
{ {

6
src/ImageSharp/Formats/Png/PngEncoderCore.cs

@ -286,7 +286,7 @@ namespace ImageSharp.Formats
// Convert the color to YCbCr and store the luminance // Convert the color to YCbCr and store the luminance
// Optionally store the original color alpha. // Optionally store the original color alpha.
int offset = x * this.bytesPerPixel; int offset = x * this.bytesPerPixel;
pixels[x, row].ToBytes(this.chunkTypeBuffer, 0, ComponentOrder.XYZW); pixels[x, row].ToXyzwBytes(this.chunkTypeBuffer, 0);
byte luminance = (byte)((0.299F * this.chunkTypeBuffer[0]) + (0.587F * this.chunkTypeBuffer[1]) + (0.114F * this.chunkTypeBuffer[2])); byte luminance = (byte)((0.299F * this.chunkTypeBuffer[0]) + (0.587F * this.chunkTypeBuffer[1]) + (0.114F * this.chunkTypeBuffer[2]));
for (int i = 0; i < this.bytesPerPixel; i++) for (int i = 0; i < this.bytesPerPixel; i++)
@ -314,7 +314,7 @@ namespace ImageSharp.Formats
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
// We can use the optimized PixelAccessor here and copy the bytes in unmanaged memory. // We can use the optimized PixelAccessor here and copy the bytes in unmanaged memory.
using (PixelArea<TColor> pixelRow = new PixelArea<TColor>(this.width, rawScanline, this.bytesPerPixel == 4 ? ComponentOrder.XYZW : ComponentOrder.XYZ)) using (PixelArea<TColor> pixelRow = new PixelArea<TColor>(this.width, rawScanline, this.bytesPerPixel == 4 ? ComponentOrder.Xyzw : ComponentOrder.Xyz))
{ {
pixels.CopyTo(pixelRow, row); pixels.CopyTo(pixelRow, row);
} }
@ -507,7 +507,7 @@ namespace ImageSharp.Formats
for (int i = 0; i < pixelCount; i++) for (int i = 0; i < pixelCount; i++)
{ {
int offset = i * 3; int offset = i * 3;
palette[i].ToBytes(bytes, 0, ComponentOrder.XYZW); palette[i].ToXyzwBytes(bytes, 0);
int alpha = bytes[3]; int alpha = bytes[3];

2
src/ImageSharp/Image/ImageBase{TColor}.cs

@ -64,7 +64,7 @@ namespace ImageSharp
using (PixelAccessor<TColor> sourcePixels = other.Lock()) using (PixelAccessor<TColor> sourcePixels = other.Lock())
using (PixelAccessor<TColor> target = this.Lock()) using (PixelAccessor<TColor> target = this.Lock())
{ {
sourcePixels.CopyImage(target); sourcePixels.CopyTo(target);
} }
} }

251
src/ImageSharp/Image/PixelAccessor{TColor}.cs

@ -145,69 +145,40 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Copies a block of pixels at the specified position. /// Copy an area of pixels to the image.
/// </summary> /// </summary>
/// <param name="sourceX">The x-coordinate of the source image.</param> /// <param name="area">The area.</param>
/// <param name="sourceY">The y-coordinate of the source image.</param> /// <param name="targetY">The target row index.</param>
/// <param name="target">The target pixel buffer accessor.</param> /// <param name="targetX">The target column index.</param>
/// <param name="targetX">The x-coordinate of the target image.</param> /// <exception cref="NotSupportedException">
/// <param name="targetY">The y-coordinate of the target image.</param> /// Thrown when an unsupported component order value is passed.
/// <param name="pixelCount">The number of pixels to copy</param> /// </exception>
public void CopyBlock(int sourceX, int sourceY, PixelAccessor<TColor> target, int targetX, int targetY, int pixelCount) public void CopyFrom(PixelArea<TColor> area, int targetY, int targetX = 0)
{ {
int size = Unsafe.SizeOf<TColor>(); this.CheckCoordinates(area, targetX, targetY);
byte* sourcePtr = this.pixelsBase + (((sourceY * this.Width) + sourceX) * size);
byte* targetPtr = target.pixelsBase + (((targetY * target.Width) + targetX) * size);
uint byteCount = (uint)(pixelCount * size);
Unsafe.CopyBlock(targetPtr, sourcePtr, byteCount);
}
/// <summary> this.CopyFrom(area, targetX, targetY, area.Width, area.Height);
/// Copies an entire image.
/// </summary>
/// <param name="target">The target pixel buffer accessor.</param>
public void CopyImage(PixelAccessor<TColor> target)
{
this.CopyBlock(0, 0, target, 0, 0, target.Width * target.Height);
} }
/// <summary> /// <summary>
/// Copied a row of pixels from the image. /// Copy pixels from the image to an area of pixels.
/// </summary> /// </summary>
/// <param name="area">The area.</param> /// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param> /// <param name="sourceY">The source row index.</param>
/// <param name="targetX">The target column index.</param> /// <param name="sourceX">The source column index.</param>
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown when an unsupported component order value is passed. /// Thrown when an unsupported component order value is passed.
/// </exception> /// </exception>
public void CopyFrom(PixelArea<TColor> area, int targetY, int targetX = 0) public void CopyTo(PixelArea<TColor> area, int sourceY, int sourceX = 0)
{ {
int width = Math.Min(area.Width, this.Width - targetX); this.CheckCoordinates(area, sourceX, sourceY);
int height = Math.Min(area.Height, this.Height - targetY);
// this.CheckDimensions(width, height); TODO: Why was width == 0 or height == 0 considered a problem? Copy implementations do not fail on this (just do nothing)! this.CopyTo(area, sourceX, sourceY, area.Width, area.Height);
switch (area.ComponentOrder)
{
case ComponentOrder.ZYX:
this.CopyFromZYX(area, targetY, targetX, width, height);
break;
case ComponentOrder.ZYXW:
this.CopyFromZYXW(area, targetY, targetX, width, height);
break;
case ComponentOrder.XYZ:
this.CopyFromXYZ(area, targetY, targetX, width, height);
break;
case ComponentOrder.XYZW:
this.CopyFromXYZW(area, targetY, targetX, width, height);
break;
default:
throw new NotSupportedException();
}
} }
/// <summary> /// <summary>
/// Copied an area of pixels to the image. /// Copy pixels from the image to an area of pixels. This method will make sure that the pixels
/// that are copied are within the bounds of the image.
/// </summary> /// </summary>
/// <param name="area">The area.</param> /// <param name="area">The area.</param>
/// <param name="sourceY">The source row index.</param> /// <param name="sourceY">The source row index.</param>
@ -215,29 +186,21 @@ namespace ImageSharp
/// <exception cref="NotSupportedException"> /// <exception cref="NotSupportedException">
/// Thrown when an unsupported component order value is passed. /// Thrown when an unsupported component order value is passed.
/// </exception> /// </exception>
public void CopyTo(PixelArea<TColor> area, int sourceY, int sourceX = 0) public void SafeCopyTo(PixelArea<TColor> area, int sourceY, int sourceX = 0)
{ {
int width = Math.Min(area.Width, this.Width - sourceX); int width = Math.Min(area.Width, this.Width - sourceX);
int height = Math.Min(area.Height, this.Height - sourceY); if (width < 1)
{
return;
}
// this.CheckDimensions(width, height); TODO: Why was width == 0 or height == 0 considered a problem? Copy implementations do not fail on this (just do nothing)! int height = Math.Min(area.Height, this.Height - sourceY);
switch (area.ComponentOrder) if (height < 1)
{ {
case ComponentOrder.ZYX: return;
this.CopyToZYX(area, sourceY, sourceX, width, height);
break;
case ComponentOrder.ZYXW:
this.CopyToZYXW(area, sourceY, sourceX, width, height);
break;
case ComponentOrder.XYZ:
this.CopyToXYZ(area, sourceY, sourceX, width, height);
break;
case ComponentOrder.XYZW:
this.CopyToXYZW(area, sourceY, sourceX, width, height);
break;
default:
throw new NotSupportedException();
} }
this.CopyTo(area, sourceX, sourceY, width, height);
} }
/// <summary> /// <summary>
@ -269,6 +232,17 @@ namespace ImageSharp
GC.SuppressFinalize(this); GC.SuppressFinalize(this);
} }
/// <summary>
/// Copies the pixels to another <see cref="PixelAccessor{TColor}"/> of the same size.
/// </summary>
/// <param name="target">The target pixel buffer accessor.</param>
internal void CopyTo(PixelAccessor<TColor> target)
{
uint byteCount = (uint)(this.Width * this.Height * Unsafe.SizeOf<TColor>());
Unsafe.CopyBlock(target.pixelsBase, this.pixelsBase, byteCount);
}
/// <summary> /// <summary>
/// Resets all the pixels to it's initial value. /// Resets all the pixels to it's initial value.
/// </summary> /// </summary>
@ -278,21 +252,21 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Copies from an area in <see cref="ComponentOrder.ZYX"/> format. /// Copies from an area in <see cref="ComponentOrder.Zyx"/> format.
/// </summary> /// </summary>
/// <param name="area">The area.</param> /// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="targetX">The target column index.</param> /// <param name="targetX">The target column index.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
protected virtual void CopyFromZYX(PixelArea<TColor> area, int targetY, int targetX, int width, int height) protected virtual void CopyFromZyx(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
{ {
TColor packed = default(TColor); TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>(); int size = Unsafe.SizeOf<TColor>();
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = area.PixelBase + (y * area.RowByteCount); byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y); byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -307,21 +281,21 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Copies from an area in <see cref="ComponentOrder.ZYXW"/> format. /// Copies from an area in <see cref="ComponentOrder.Zyxw"/> format.
/// </summary> /// </summary>
/// <param name="area">The area.</param> /// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="targetX">The target column index.</param> /// <param name="targetX">The target column index.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
protected virtual void CopyFromZYXW(PixelArea<TColor> area, int targetY, int targetX, int width, int height) protected virtual void CopyFromZyxw(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
{ {
TColor packed = default(TColor); TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>(); int size = Unsafe.SizeOf<TColor>();
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = area.PixelBase + (y * area.RowByteCount); byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y); byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -336,21 +310,21 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Copies from an area in <see cref="ComponentOrder.XYZ"/> format. /// Copies from an area in <see cref="ComponentOrder.Xyz"/> format.
/// </summary> /// </summary>
/// <param name="area">The area.</param> /// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="targetX">The target column index.</param> /// <param name="targetX">The target column index.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
protected virtual void CopyFromXYZ(PixelArea<TColor> area, int targetY, int targetX, int width, int height) protected virtual void CopyFromXyz(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
{ {
TColor packed = default(TColor); TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>(); int size = Unsafe.SizeOf<TColor>();
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = area.PixelBase + (y * area.RowByteCount); byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y); byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -365,21 +339,21 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Copies from an area in <see cref="ComponentOrder.XYZW"/> format. /// Copies from an area in <see cref="ComponentOrder.Xyzw"/> format.
/// </summary> /// </summary>
/// <param name="area">The area.</param> /// <param name="area">The area.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="targetX">The target column index.</param> /// <param name="targetX">The target column index.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
protected virtual void CopyFromXYZW(PixelArea<TColor> area, int targetY, int targetX, int width, int height) protected virtual void CopyFromXyzw(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
{ {
TColor packed = default(TColor); TColor packed = default(TColor);
int size = Unsafe.SizeOf<TColor>(); int size = Unsafe.SizeOf<TColor>();
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = area.PixelBase + (y * area.RowByteCount); byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y); byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -394,84 +368,84 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Copies to an area in <see cref="ComponentOrder.ZYX"/> format. /// Copies to an area in <see cref="ComponentOrder.Zyx"/> format.
/// </summary> /// </summary>
/// <param name="area">The row.</param> /// <param name="area">The row.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="sourceX">The source column index.</param> /// <param name="sourceX">The source column index.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
protected virtual void CopyToZYX(PixelArea<TColor> area, int sourceY, int sourceX, int width, int height) protected virtual void CopyToZyx(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
int offset = y * area.RowByteCount; int offset = y * area.RowStride;
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
this[sourceX + x, sourceY + y].ToBytes(area.Bytes, offset, ComponentOrder.ZYX); this[sourceX + x, sourceY + y].ToZyxBytes(area.Bytes, offset);
offset += 3; offset += 3;
} }
} }
} }
/// <summary> /// <summary>
/// Copies to an area in <see cref="ComponentOrder.ZYXW"/> format. /// Copies to an area in <see cref="ComponentOrder.Zyxw"/> format.
/// </summary> /// </summary>
/// <param name="area">The row.</param> /// <param name="area">The row.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="sourceX">The source column index.</param> /// <param name="sourceX">The source column index.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
protected virtual void CopyToZYXW(PixelArea<TColor> area, int sourceY, int sourceX, int width, int height) protected virtual void CopyToZyxw(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
int offset = y * area.RowByteCount; int offset = y * area.RowStride;
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
this[sourceX + x, sourceY + y].ToBytes(area.Bytes, offset, ComponentOrder.ZYXW); this[sourceX + x, sourceY + y].ToZyxwBytes(area.Bytes, offset);
offset += 4; offset += 4;
} }
} }
} }
/// <summary> /// <summary>
/// Copies to an area in <see cref="ComponentOrder.XYZ"/> format. /// Copies to an area in <see cref="ComponentOrder.Xyz"/> format.
/// </summary> /// </summary>
/// <param name="area">The row.</param> /// <param name="area">The row.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="sourceX">The source column index.</param> /// <param name="sourceX">The source column index.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
protected virtual void CopyToXYZ(PixelArea<TColor> area, int sourceY, int sourceX, int width, int height) protected virtual void CopyToXyz(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
int offset = y * area.RowByteCount; int offset = y * area.RowStride;
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
this[sourceX + x, sourceY + y].ToBytes(area.Bytes, offset, ComponentOrder.XYZ); this[sourceX + x, sourceY + y].ToXyzBytes(area.Bytes, offset);
offset += 3; offset += 3;
} }
} }
} }
/// <summary> /// <summary>
/// Copies to an area in <see cref="ComponentOrder.XYZW"/> format. /// Copies to an area in <see cref="ComponentOrder.Xyzw"/> format.
/// </summary> /// </summary>
/// <param name="area">The row.</param> /// <param name="area">The row.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="sourceX">The source column index.</param> /// <param name="sourceX">The source column index.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
protected virtual void CopyToXYZW(PixelArea<TColor> area, int sourceY, int sourceX, int width, int height) protected virtual void CopyToXyzw(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
int offset = y * area.RowByteCount; int offset = y * area.RowStride;
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
this[sourceX + x, sourceY + y].ToBytes(area.Bytes, offset, ComponentOrder.XYZW); this[sourceX + x, sourceY + y].ToXyzwBytes(area.Bytes, offset);
offset += 4; offset += 4;
} }
} }
@ -491,21 +465,88 @@ namespace ImageSharp
} }
/// <summary> /// <summary>
/// Checks that the given dimensions are within the bounds of the image. /// Copy an area of pixels to the image.
/// </summary> /// </summary>
/// <param name="width">The width.</param> /// <param name="area">The area.</param>
/// <param name="height">The height.</param> /// <param name="targetX">The target column index.</param>
/// <param name="targetY">The target row index.</param>
/// <param name="width">The width of the area to copy.</param>
/// <param name="height">The height of the area to copy.</param>
/// <exception cref="NotSupportedException">
/// Thrown when an unsupported component order value is passed.
/// </exception>
private void CopyFrom(PixelArea<TColor> area, int targetX, int targetY, int width, int height)
{
switch (area.ComponentOrder)
{
case ComponentOrder.Zyx:
this.CopyFromZyx(area, targetX, targetY, width, height);
break;
case ComponentOrder.Zyxw:
this.CopyFromZyxw(area, targetX, targetY, width, height);
break;
case ComponentOrder.Xyz:
this.CopyFromXyz(area, targetX, targetY, width, height);
break;
case ComponentOrder.Xyzw:
this.CopyFromXyzw(area, targetX, targetY, width, height);
break;
default:
throw new NotSupportedException();
}
}
/// <summary>
/// Copy pixels from the image to an area of pixels.
/// </summary>
/// <param name="area">The area.</param>
/// <param name="sourceX">The source column index.</param>
/// <param name="sourceY">The source row index.</param>
/// <param name="width">The width of the area to copy.</param>
/// <param name="height">The height of the area to copy.</param>
/// <exception cref="NotSupportedException">
/// Thrown when an unsupported component order value is passed.
/// </exception>
private void CopyTo(PixelArea<TColor> area, int sourceX, int sourceY, int width, int height)
{
switch (area.ComponentOrder)
{
case ComponentOrder.Zyx:
this.CopyToZyx(area, sourceX, sourceY, width, height);
break;
case ComponentOrder.Zyxw:
this.CopyToZyxw(area, sourceX, sourceY, width, height);
break;
case ComponentOrder.Xyz:
this.CopyToXyz(area, sourceX, sourceY, width, height);
break;
case ComponentOrder.Xyzw:
this.CopyToXyzw(area, sourceX, sourceY, width, height);
break;
default:
throw new NotSupportedException();
}
}
/// <summary>
/// Checks that the given area and offset are within the bounds of the image.
/// </summary>
/// <param name="area">The area.</param>
/// <param name="x">The x-coordinate of the pixel. Must be greater than zero and smaller than the width of the pixel.</param>
/// <param name="y">The y-coordinate of the pixel. Must be greater than zero and smaller than the width of the pixel.</param>
/// <exception cref="ArgumentOutOfRangeException"> /// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the dimensions are not within the bounds of the image. /// Thrown if the dimensions are not within the bounds of the image.
/// </exception> /// </exception>
[Conditional("DEBUG")] [Conditional("DEBUG")]
private void CheckDimensions(int width, int height) private void CheckCoordinates(PixelArea<TColor> area, int x, int y)
{ {
int width = Math.Min(area.Width, this.Width - x);
if (width < 1) if (width < 1)
{ {
throw new ArgumentOutOfRangeException(nameof(width), width, $"Invalid area size specified."); throw new ArgumentOutOfRangeException(nameof(width), width, $"Invalid area size specified.");
} }
int height = Math.Min(area.Height, this.Height - y);
if (height < 1) if (height < 1)
{ {
throw new ArgumentOutOfRangeException(nameof(height), height, $"Invalid area size specified."); throw new ArgumentOutOfRangeException(nameof(height), height, $"Invalid area size specified.");

114
src/ImageSharp/Image/PixelArea{TColor}.cs

@ -18,6 +18,11 @@ namespace ImageSharp
public sealed unsafe class PixelArea<TColor> : IDisposable public sealed unsafe class PixelArea<TColor> : IDisposable
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
/// <summary>
/// True if <see cref="Bytes"/> was rented from <see cref="BytesPool"/> by the constructor
/// </summary>
private readonly bool isBufferRented;
/// <summary> /// <summary>
/// Provides a way to access the pixels from unmanaged memory. /// Provides a way to access the pixels from unmanaged memory.
/// </summary> /// </summary>
@ -28,11 +33,6 @@ namespace ImageSharp
/// </summary> /// </summary>
private IntPtr dataPointer; private IntPtr dataPointer;
/// <summary>
/// True if <see cref="Bytes"/> was rented from <see cref="BytesPool"/> by the constructor
/// </summary>
private bool isBufferRented;
/// <summary> /// <summary>
/// A value indicating whether this instance of the given entity has been disposed. /// A value indicating whether this instance of the given entity has been disposed.
/// </summary> /// </summary>
@ -75,8 +75,10 @@ namespace ImageSharp
this.Width = width; this.Width = width;
this.Height = height; this.Height = height;
this.ComponentOrder = componentOrder; this.ComponentOrder = componentOrder;
this.RowByteCount = width * GetComponentCount(componentOrder); this.RowStride = width * GetComponentCount(componentOrder);
this.Bytes = bytes; this.Bytes = bytes;
this.Length = bytes.Length;
this.isBufferRented = false;
this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned); this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned);
// TODO: Why is Resharper warning us about an impure method call? // TODO: Why is Resharper warning us about an impure method call?
@ -88,34 +90,31 @@ namespace ImageSharp
/// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class. /// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class.
/// </summary> /// </summary>
/// <param name="width">The width.</param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="componentOrder">The component order.</param> /// <param name="componentOrder">The component order.</param>
/// <param name="usePool">True if the buffer should be rented from ArrayPool</param> public PixelArea(int width, ComponentOrder componentOrder)
public PixelArea(int width, int height, ComponentOrder componentOrder, bool usePool = false) : this(width, 1, componentOrder, 0)
: this(width, height, componentOrder, 0, usePool)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class. /// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class.
/// </summary> /// </summary>
/// <param name="width">The width.</param> /// <param name="width">The width. </param>
/// <param name="componentOrder">The component order.</param> /// <param name="componentOrder">The component order.</param>
/// <param name="usePool">True if the buffer should be rented from ArrayPool</param> /// <param name="padding">The number of bytes to pad each row.</param>
public PixelArea(int width, ComponentOrder componentOrder, bool usePool = false) public PixelArea(int width, ComponentOrder componentOrder, int padding)
: this(width, 1, componentOrder, 0, usePool) : this(width, 1, componentOrder, padding)
{ {
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class. /// Initializes a new instance of the <see cref="PixelArea{TColor}"/> class.
/// </summary> /// </summary>
/// <param name="width">The width. </param> /// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="componentOrder">The component order.</param> /// <param name="componentOrder">The component order.</param>
/// <param name="padding">The number of bytes to pad each row.</param> public PixelArea(int width, int height, ComponentOrder componentOrder)
/// <param name="usePool">True if the buffer should be rented from ArrayPool</param> : this(width, height, componentOrder, 0)
public PixelArea(int width, ComponentOrder componentOrder, int padding, bool usePool = false)
: this(width, 1, componentOrder, padding, usePool)
{ {
} }
@ -126,27 +125,15 @@ namespace ImageSharp
/// <param name="height">The height.</param> /// <param name="height">The height.</param>
/// <param name="componentOrder">The component order.</param> /// <param name="componentOrder">The component order.</param>
/// <param name="padding">The number of bytes to pad each row.</param> /// <param name="padding">The number of bytes to pad each row.</param>
/// <param name="usePool">True if the buffer should be rented from ArrayPool</param> public PixelArea(int width, int height, ComponentOrder componentOrder, int padding)
public PixelArea(int width, int height, ComponentOrder componentOrder, int padding, bool usePool = false)
{ {
this.Width = width; this.Width = width;
this.Height = height; this.Height = height;
this.ComponentOrder = componentOrder; this.ComponentOrder = componentOrder;
this.RowByteCount = (width * GetComponentCount(componentOrder)) + padding; this.RowStride = (width * GetComponentCount(componentOrder)) + padding;
this.Length = this.RowStride * height;
int bufferSize = this.RowByteCount * height; this.Bytes = BytesPool.Rent(this.Length);
this.isBufferRented = true;
if (usePool)
{
this.Bytes = BytesPool.Rent(bufferSize);
this.isBufferRented = true;
Array.Clear(this.Bytes, 0, bufferSize);
}
else
{
this.Bytes = new byte[bufferSize];
}
this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned); this.pixelsHandle = GCHandle.Alloc(this.Bytes, GCHandleType.Pinned);
// TODO: Why is Resharper warning us about an impure method call? // TODO: Why is Resharper warning us about an impure method call?
@ -167,6 +154,11 @@ namespace ImageSharp
/// </summary> /// </summary>
public byte[] Bytes { get; } public byte[] Bytes { get; }
/// <summary>
/// Gets the length of the buffer.
/// </summary>
public int Length { get; }
/// <summary> /// <summary>
/// Gets the component order. /// Gets the component order.
/// </summary> /// </summary>
@ -188,9 +180,9 @@ namespace ImageSharp
public byte* PixelBase { get; private set; } public byte* PixelBase { get; private set; }
/// <summary> /// <summary>
/// Gets number of bytes in a row. /// Gets the width of one row in the number of bytes.
/// </summary> /// </summary>
public int RowByteCount { get; } public int RowStride { get; }
/// <summary> /// <summary>
/// Gets the width. /// Gets the width.
@ -198,9 +190,9 @@ namespace ImageSharp
public int Width { get; } public int Width { get; }
/// <summary> /// <summary>
/// Gets the pool used to rent <see cref="Bytes"/>, when it's not coming from an external source /// Gets the pool used to rent bytes, when it's not coming from an external source.
/// </summary> /// </summary>
// ReSharper disable once StaticMemberInGenericType // TODO: Use own pool?
private static ArrayPool<byte> BytesPool => ArrayPool<byte>.Shared; private static ArrayPool<byte> BytesPool => ArrayPool<byte>.Shared;
/// <summary> /// <summary>
@ -209,6 +201,13 @@ namespace ImageSharp
public void Dispose() public void Dispose()
{ {
this.Dispose(true); this.Dispose(true);
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SuppressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
} }
/// <summary> /// <summary>
@ -217,7 +216,7 @@ namespace ImageSharp
/// <param name="stream">The stream.</param> /// <param name="stream">The stream.</param>
public void Read(Stream stream) public void Read(Stream stream)
{ {
stream.Read(this.Bytes, 0, this.Bytes.Length); stream.Read(this.Bytes, 0, this.Length);
} }
/// <summary> /// <summary>
@ -226,7 +225,7 @@ namespace ImageSharp
/// <param name="stream">The stream.</param> /// <param name="stream">The stream.</param>
public void Write(Stream stream) public void Write(Stream stream)
{ {
stream.Write(this.Bytes, 0, this.Bytes.Length); stream.Write(this.Bytes, 0, this.Length);
} }
/// <summary> /// <summary>
@ -234,7 +233,7 @@ namespace ImageSharp
/// </summary> /// </summary>
internal void Reset() internal void Reset()
{ {
Unsafe.InitBlock(this.PixelBase, 0, (uint)(this.RowByteCount * this.Height)); Unsafe.InitBlock(this.PixelBase, 0, (uint)(this.RowStride * this.Height));
} }
/// <summary> /// <summary>
@ -251,17 +250,27 @@ namespace ImageSharp
{ {
switch (componentOrder) switch (componentOrder)
{ {
case ComponentOrder.ZYX: case ComponentOrder.Zyx:
case ComponentOrder.XYZ: case ComponentOrder.Xyz:
return 3; return 3;
case ComponentOrder.ZYXW: case ComponentOrder.Zyxw:
case ComponentOrder.XYZW: case ComponentOrder.Xyzw:
return 4; return 4;
} }
throw new NotSupportedException(); throw new NotSupportedException();
} }
/// <summary>
/// Checks that the length of the byte array to ensure that it matches the given width and height.
/// </summary>
/// <param name="width">The width.</param>
/// <param name="height">The height.</param>
/// <param name="bytes">The byte array.</param>
/// <param name="componentOrder">The component order.</param>
/// <exception cref="ArgumentOutOfRangeException">
/// Thrown if the byte array is th incorrect length.
/// </exception>
[Conditional("DEBUG")] [Conditional("DEBUG")]
private void CheckBytesLength(int width, int height, byte[] bytes, ComponentOrder componentOrder) private void CheckBytesLength(int width, int height, byte[] bytes, ComponentOrder componentOrder)
{ {
@ -274,6 +283,10 @@ namespace ImageSharp
} }
} }
/// <summary>
/// Disposes the object and frees resources for the Garbage Collector.
/// </summary>
/// <param name="disposing">If true, the object gets disposed.</param>
private void Dispose(bool disposing) private void Dispose(bool disposing)
{ {
if (this.isDisposed) if (this.isDisposed)
@ -300,13 +313,6 @@ namespace ImageSharp
this.PixelBase = null; this.PixelBase = null;
this.isDisposed = true; this.isDisposed = true;
// This object will be cleaned up by the Dispose method.
// Therefore, you should call GC.SuppressFinalize to
// take this object off the finalization queue
// and prevent finalization code for this object
// from executing a second time.
GC.SuppressFinalize(this);
} }
} }
} }

28
src/ImageSharp/PixelAccessor.cs

@ -22,13 +22,13 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void CopyFromXYZW(PixelArea<Color> area, int targetY, int targetX, int width, int height) protected override void CopyFromXyzw(PixelArea<Color> area, int targetX, int targetY, int width, int height)
{ {
uint byteCount = (uint)width * 4; uint byteCount = (uint)width * 4;
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = area.PixelBase + (y * area.RowByteCount); byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y); byte* destination = this.GetRowPointer(targetX, targetY + y);
Unsafe.CopyBlock(destination, source, byteCount); Unsafe.CopyBlock(destination, source, byteCount);
@ -36,11 +36,11 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void CopyFromXYZ(PixelArea<Color> area, int targetY, int targetX, int width, int height) protected override void CopyFromXyz(PixelArea<Color> area, int targetX, int targetY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = area.PixelBase + (y * area.RowByteCount); byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y); byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -54,11 +54,11 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void CopyFromZYX(PixelArea<Color> area, int targetY, int targetX, int width, int height) protected override void CopyFromZyx(PixelArea<Color> area, int targetX, int targetY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = area.PixelBase + (y * area.RowByteCount); byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y); byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -72,11 +72,11 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void CopyFromZYXW(PixelArea<Color> area, int targetY, int targetX, int width, int height) protected override void CopyFromZyxw(PixelArea<Color> area, int targetX, int targetY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = area.PixelBase + (y * area.RowByteCount); byte* source = area.PixelBase + (y * area.RowStride);
byte* destination = this.GetRowPointer(targetX, targetY + y); byte* destination = this.GetRowPointer(targetX, targetY + y);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
@ -90,12 +90,12 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void CopyToZYX(PixelArea<Color> area, int sourceY, int sourceX, int width, int height) protected override void CopyToZyx(PixelArea<Color> area, int sourceX, int sourceY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = this.GetRowPointer(sourceX, sourceY + y); byte* source = this.GetRowPointer(sourceX, sourceY + y);
byte* destination = area.PixelBase + (y * area.RowByteCount); byte* destination = area.PixelBase + (y * area.RowStride);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
@ -110,12 +110,12 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
protected override unsafe void CopyToXYZ(PixelArea<Color> area, int sourceY, int sourceX, int width, int height) protected override void CopyToXyz(PixelArea<Color> area, int sourceX, int sourceY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = this.GetRowPointer(sourceX, sourceY + y); byte* source = this.GetRowPointer(sourceX, sourceY + y);
byte* destination = area.PixelBase + (y * area.RowByteCount); byte* destination = area.PixelBase + (y * area.RowStride);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
@ -130,12 +130,12 @@ namespace ImageSharp
} }
/// <inheritdoc /> /// <inheritdoc />
protected override void CopyToZYXW(PixelArea<Color> area, int sourceY, int sourceX, int width, int height) protected override void CopyToZyxw(PixelArea<Color> area, int sourceX, int sourceY, int width, int height)
{ {
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
{ {
byte* source = this.GetRowPointer(sourceX, sourceY + y); byte* source = this.GetRowPointer(sourceX, sourceY + y);
byte* destination = area.PixelBase + (y * area.RowByteCount); byte* destination = area.PixelBase + (y * area.RowStride);
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {

50
src/ImageSharp/Profiles/Exif/ExifTag.cs

@ -29,15 +29,15 @@ namespace ImageSharp
/// <summary> /// <summary>
/// SubfileType /// SubfileType
/// </summary> /// </summary>
[ExifTagDescription((uint)0, "Full-resolution Image")] [ExifTagDescription(0U, "Full-resolution Image")]
[ExifTagDescription((uint)1, "Reduced-resolution image")] [ExifTagDescription(1U, "Reduced-resolution image")]
[ExifTagDescription((uint)2, "Single page of multi-page image")] [ExifTagDescription(2U, "Single page of multi-page image")]
[ExifTagDescription((uint)3, "Single page of multi-page reduced-resolution image")] [ExifTagDescription(3U, "Single page of multi-page reduced-resolution image")]
[ExifTagDescription((uint)4, "Transparency mask")] [ExifTagDescription(4U, "Transparency mask")]
[ExifTagDescription((uint)5, "Transparency mask of reduced-resolution image")] [ExifTagDescription(5U, "Transparency mask of reduced-resolution image")]
[ExifTagDescription((uint)6, "Transparency mask of multi-page image")] [ExifTagDescription(6U, "Transparency mask of multi-page image")]
[ExifTagDescription((uint)7, "Transparency mask of reduced-resolution multi-page image")] [ExifTagDescription(7U, "Transparency mask of reduced-resolution multi-page image")]
[ExifTagDescription((uint)0x10001, "Alternate reduced-resolution image ")] [ExifTagDescription(0x10001U, "Alternate reduced-resolution image ")]
SubfileType = 0x00FE, SubfileType = 0x00FE,
/// <summary> /// <summary>
@ -276,15 +276,15 @@ namespace ImageSharp
/// <summary> /// <summary>
/// T4Options /// T4Options
/// </summary> /// </summary>
[ExifTagDescription((uint)0, "2-Dimensional encoding")] [ExifTagDescription(0U, "2-Dimensional encoding")]
[ExifTagDescription((uint)1, "Uncompressed")] [ExifTagDescription(1U, "Uncompressed")]
[ExifTagDescription((uint)2, "Fill bits added")] [ExifTagDescription(2U, "Fill bits added")]
T4Options = 0x0124, T4Options = 0x0124,
/// <summary> /// <summary>
/// T6Options /// T6Options
/// </summary> /// </summary>
[ExifTagDescription((uint)1, "Uncompressed")] [ExifTagDescription(1U, "Uncompressed")]
T6Options = 0x0125, T6Options = 0x0125,
/// <summary> /// <summary>
@ -383,9 +383,9 @@ namespace ImageSharp
/// <summary> /// <summary>
/// CleanFaxData /// CleanFaxData
/// </summary> /// </summary>
[ExifTagDescription((uint)0, "Clean")] [ExifTagDescription(0U, "Clean")]
[ExifTagDescription((uint)1, "Regenerated")] [ExifTagDescription(1U, "Regenerated")]
[ExifTagDescription((uint)2, "Unclean")] [ExifTagDescription(2U, "Unclean")]
CleanFaxData = 0x0147, CleanFaxData = 0x0147,
/// <summary> /// <summary>
@ -491,8 +491,8 @@ namespace ImageSharp
/// <summary> /// <summary>
/// ProfileType /// ProfileType
/// </summary> /// </summary>
[ExifTagDescription((uint)0, "Unspecified")] [ExifTagDescription(0U, "Unspecified")]
[ExifTagDescription((uint)1, "Group 3 FAX")] [ExifTagDescription(1U, "Group 3 FAX")]
ProfileType = 0x0191, ProfileType = 0x0191,
/// <summary> /// <summary>
@ -512,13 +512,13 @@ namespace ImageSharp
/// <summary> /// <summary>
/// CodingMethods /// CodingMethods
/// </summary> /// </summary>
[ExifTagDescription((ulong)0, "Unspecified compression")] [ExifTagDescription(0UL, "Unspecified compression")]
[ExifTagDescription((ulong)1, "Modified Huffman")] [ExifTagDescription(1UL, "Modified Huffman")]
[ExifTagDescription((ulong)2, "Modified Read")] [ExifTagDescription(2UL, "Modified Read")]
[ExifTagDescription((ulong)4, "Modified MR")] [ExifTagDescription(4UL, "Modified MR")]
[ExifTagDescription((ulong)8, "JBIG")] [ExifTagDescription(8UL, "JBIG")]
[ExifTagDescription((ulong)16, "Baseline JPEG")] [ExifTagDescription(16UL, "Baseline JPEG")]
[ExifTagDescription((ulong)32, "JBIG color")] [ExifTagDescription(32UL, "JBIG color")]
CodingMethods = 0x0193, CodingMethods = 0x0193,
/// <summary> /// <summary>

14
src/ImageSharp/Quantizers/Octree/OctreeQuantizer.cs

@ -47,12 +47,7 @@ namespace ImageSharp.Quantizers
public override QuantizedImage<TColor> Quantize(ImageBase<TColor> image, int maxColors) public override QuantizedImage<TColor> Quantize(ImageBase<TColor> image, int maxColors)
{ {
this.colors = maxColors.Clamp(1, 255); this.colors = maxColors.Clamp(1, 255);
this.octree = new Octree(this.GetBitsNeededForColorDepth(maxColors));
if (this.octree == null)
{
// Construct the Octree
this.octree = new Octree(this.GetBitsNeededForColorDepth(maxColors));
}
return base.Quantize(image, maxColors); return base.Quantize(image, maxColors);
} }
@ -117,6 +112,7 @@ namespace ImageSharp.Quantizers
/// <summary> /// <summary>
/// Mask used when getting the appropriate pixels for a given node /// Mask used when getting the appropriate pixels for a given node
/// </summary> /// </summary>
// ReSharper disable once StaticMemberInGenericType
private static readonly int[] Mask = { 0x100, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 }; private static readonly int[] Mask = { 0x100, 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
/// <summary> /// <summary>
@ -380,7 +376,7 @@ namespace ImageSharp.Quantizers
{ {
// Go to the next level down in the tree // Go to the next level down in the tree
int shift = 7 - level; int shift = 7 - level;
pixel.ToBytes(buffer, 0, ComponentOrder.XYZW); pixel.ToXyzwBytes(buffer, 0);
int index = ((buffer[3] & Mask[0]) >> (shift - 3)) | int index = ((buffer[3] & Mask[0]) >> (shift - 3)) |
((buffer[2] & Mask[level + 1]) >> (shift - 2)) | ((buffer[2] & Mask[level + 1]) >> (shift - 2)) |
@ -484,7 +480,7 @@ namespace ImageSharp.Quantizers
if (!this.leaf) if (!this.leaf)
{ {
int shift = 7 - level; int shift = 7 - level;
pixel.ToBytes(buffer, 0, ComponentOrder.XYZW); pixel.ToXyzwBytes(buffer, 0);
int pixelIndex = ((buffer[3] & Mask[0]) >> (shift - 3)) | int pixelIndex = ((buffer[3] & Mask[0]) >> (shift - 3)) |
((buffer[2] & Mask[level + 1]) >> (shift - 2)) | ((buffer[2] & Mask[level + 1]) >> (shift - 2)) |
@ -511,7 +507,7 @@ namespace ImageSharp.Quantizers
/// <param name="buffer">The buffer array.</param> /// <param name="buffer">The buffer array.</param>
public void Increment(TColor pixel, byte[] buffer) public void Increment(TColor pixel, byte[] buffer)
{ {
pixel.ToBytes(buffer, 0, ComponentOrder.XYZW); pixel.ToXyzwBytes(buffer, 0);
this.pixelCount++; this.pixelCount++;
this.red += buffer[0]; this.red += buffer[0];
this.green += buffer[1]; this.green += buffer[1];

2
src/ImageSharp/Quantizers/Palette/PaletteQuantizer.cs

@ -49,7 +49,7 @@ namespace ImageSharp.Quantizers
for (int i = 0; i < constants.Length; i++) for (int i = 0; i < constants.Length; i++)
{ {
constants[i].ToBytes(this.pixelBuffer, 0, ComponentOrder.XYZW); constants[i].ToXyzwBytes(this.pixelBuffer, 0);
TColor packed = default(TColor); TColor packed = default(TColor);
packed.PackFromBytes(this.pixelBuffer[0], this.pixelBuffer[1], this.pixelBuffer[2], this.pixelBuffer[3]); packed.PackFromBytes(this.pixelBuffer[0], this.pixelBuffer[1], this.pixelBuffer[2], this.pixelBuffer[3]);
safe[i] = packed; safe[i] = packed;

15
src/ImageSharp/Quantizers/Wu/WuQuantizer.cs

@ -33,11 +33,6 @@ namespace ImageSharp.Quantizers
public sealed class WuQuantizer<TColor> : IQuantizer<TColor> public sealed class WuQuantizer<TColor> : IQuantizer<TColor>
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
/// <summary>
/// The epsilon for comparing floating point numbers.
/// </summary>
private const float Epsilon = 1e-5F;
/// <summary> /// <summary>
/// The index bits. /// The index bits.
/// </summary> /// </summary>
@ -340,7 +335,7 @@ namespace ImageSharp.Quantizers
for (int x = 0; x < pixels.Width; x++) for (int x = 0; x < pixels.Width; x++)
{ {
// Colors are expected in r->g->b->a format // Colors are expected in r->g->b->a format
pixels[x, y].ToBytes(this.rgbaBuffer, 0, ComponentOrder.XYZW); pixels[x, y].ToXyzwBytes(this.rgbaBuffer, 0);
byte r = this.rgbaBuffer[0]; byte r = this.rgbaBuffer[0];
byte g = this.rgbaBuffer[1]; byte g = this.rgbaBuffer[1];
@ -542,7 +537,7 @@ namespace ImageSharp.Quantizers
double temp; double temp;
if (Math.Abs(halfW) < Epsilon) if (Math.Abs(halfW) < Constants.Epsilon)
{ {
continue; continue;
} }
@ -555,7 +550,7 @@ namespace ImageSharp.Quantizers
halfA = wholeA - halfA; halfA = wholeA - halfA;
halfW = wholeW - halfW; halfW = wholeW - halfW;
if (Math.Abs(halfW) < Epsilon) if (Math.Abs(halfW) < Constants.Epsilon)
{ {
continue; continue;
} }
@ -762,7 +757,7 @@ namespace ImageSharp.Quantizers
double weight = Volume(cube[k], this.vwt); double weight = Volume(cube[k], this.vwt);
if (Math.Abs(weight) > Epsilon) if (Math.Abs(weight) > Constants.Epsilon)
{ {
float r = (float)(Volume(cube[k], this.vmr) / weight); float r = (float)(Volume(cube[k], this.vmr) / weight);
float g = (float)(Volume(cube[k], this.vmg) / weight); float g = (float)(Volume(cube[k], this.vmg) / weight);
@ -785,7 +780,7 @@ namespace ImageSharp.Quantizers
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
// Expected order r->g->b->a // Expected order r->g->b->a
imagePixels[x, y].ToBytes(rgba, 0, ComponentOrder.XYZW); imagePixels[x, y].ToXyzwBytes(rgba, 0);
int r = rgba[0] >> (8 - IndexBits); int r = rgba[0] >> (8 - IndexBits);
int g = rgba[1] >> (8 - IndexBits); int g = rgba[1] >> (8 - IndexBits);

4
src/ImageSharp/project.json

@ -24,7 +24,7 @@
"buildOptions": { "buildOptions": {
"allowUnsafe": true, "allowUnsafe": true,
"xmlDoc": true, "xmlDoc": true,
"additionalArguments": [ "/additionalfile:stylecop.json" ] "additionalArguments": [ "/additionalfile:stylecop.json", "/ruleset:../../ImageSharp.ruleset" ]
}, },
"configurations": { "configurations": {
"Release": { "Release": {
@ -36,7 +36,7 @@
}, },
"dependencies": { "dependencies": {
"StyleCop.Analyzers": { "StyleCop.Analyzers": {
"version": "1.0.0", "version": "1.1.0-beta001",
"type": "build" "type": "build"
}, },
"System.Buffers": "4.0.0", "System.Buffers": "4.0.0",

21
tests/ImageSharp.Benchmarks/Image/CopyPixels.cs

@ -37,26 +37,5 @@ namespace ImageSharp.Benchmarks.Image
return targetPixels[0, 0]; return targetPixels[0, 0];
} }
} }
[Benchmark(Description = "Copy by Row")]
public CoreColor CopyByRow()
{
CoreImage source = new CoreImage(1024, 768);
CoreImage target = new CoreImage(1024, 768);
using (PixelAccessor<CoreColor> sourcePixels = source.Lock())
using (PixelAccessor<CoreColor> targetPixels = target.Lock())
{
Parallel.For(
0,
source.Height,
Bootstrapper.ParallelOptions,
y =>
{
sourcePixels.CopyBlock(0, y, targetPixels, 0, y, source.Width);
});
return targetPixels[0, 0];
}
}
} }
} }

2
tests/ImageSharp.Tests/Colors/ColorConversionTests.cs

@ -7,7 +7,7 @@ namespace ImageSharp.Tests
{ {
using System; using System;
using System.Diagnostics.CodeAnalysis; using System.Diagnostics.CodeAnalysis;
using ImageSharp.Colors.Spaces;
using Xunit; using Xunit;
/// <summary> /// <summary>

165
tests/ImageSharp.Tests/Colors/PackedPixelTests.cs

@ -15,7 +15,7 @@ namespace ImageSharp.Tests.Colors
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// The "ToVector4" tests should now be covered in <see cref="ColorConstructorTests"/> /// The "ToVector4" tests should now be covered in <see cref="ColorConstructorTests"/>
/// and at some point they can be safely removed from here. /// and at some point they can be safely removed from here.
/// </remarks> /// </remarks>
public class PackedPixelTests public class PackedPixelTests
{ {
@ -47,16 +47,16 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Alpha8(.5F).ToBytes(rgb, 0, ComponentOrder.XYZ); new Alpha8(.5F).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 0, 0, 0 }); Assert.Equal(rgb, new byte[] { 0, 0, 0 });
new Alpha8(.5F).ToBytes(rgba, 0, ComponentOrder.XYZW); new Alpha8(.5F).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 0, 0, 0, 128 }); Assert.Equal(rgba, new byte[] { 0, 0, 0, 128 });
new Alpha8(.5F).ToBytes(bgr, 0, ComponentOrder.ZYX); new Alpha8(.5F).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 0, 0 }); Assert.Equal(bgr, new byte[] { 0, 0, 0 });
new Alpha8(.5F).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Alpha8(.5F).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 0, 0, 128 }); Assert.Equal(bgra, new byte[] { 0, 0, 0, 128 });
} }
@ -92,16 +92,16 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
argb.ToBytes(rgb, 0, ComponentOrder.XYZ); argb.ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 0x1a, 0, 0x80 }); Assert.Equal(rgb, new byte[] { 0x1a, 0, 0x80 });
argb.ToBytes(rgba, 0, ComponentOrder.XYZW); argb.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 0x1a, 0, 0x80, 0 }); Assert.Equal(rgba, new byte[] { 0x1a, 0, 0x80, 0 });
argb.ToBytes(bgr, 0, ComponentOrder.ZYX); argb.ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0x80, 0, 0x1a }); Assert.Equal(bgr, new byte[] { 0x80, 0, 0x1a });
argb.ToBytes(bgra, 0, ComponentOrder.ZYXW); argb.ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0x80, 0, 0x1a, 0 }); Assert.Equal(bgra, new byte[] { 0x80, 0, 0x1a, 0 });
} }
@ -133,23 +133,22 @@ namespace ImageSharp.Tests.Colors
float z = 0.5F; float z = 0.5F;
Assert.Equal(6160, new Bgr565(x, y, z).PackedValue); Assert.Equal(6160, new Bgr565(x, y, z).PackedValue);
// Test ordering // Test ordering
byte[] rgb = new byte[3]; byte[] rgb = new byte[3];
byte[] rgba = new byte[4]; byte[] rgba = new byte[4];
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Bgr565(x, y, z).ToBytes(rgb, 0, ComponentOrder.XYZ); new Bgr565(x, y, z).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 25, 0, 132 }); Assert.Equal(rgb, new byte[] { 25, 0, 132 });
new Bgr565(x, y, z).ToBytes(rgba, 0, ComponentOrder.XYZW); new Bgr565(x, y, z).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 25, 0, 132, 255 }); Assert.Equal(rgba, new byte[] { 25, 0, 132, 255 });
new Bgr565(x, y, z).ToBytes(bgr, 0, ComponentOrder.ZYX); new Bgr565(x, y, z).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 132, 0, 25 }); Assert.Equal(bgr, new byte[] { 132, 0, 25 });
new Bgr565(x, y, z).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Bgr565(x, y, z).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 132, 0, 25, 255 }); Assert.Equal(bgra, new byte[] { 132, 0, 25, 255 });
} }
@ -190,16 +189,16 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Bgra4444(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); new Bgra4444(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 34, 0, 136 }); Assert.Equal(rgb, new byte[] { 34, 0, 136 });
new Bgra4444(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); new Bgra4444(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 34, 0, 136, 0 }); Assert.Equal(rgba, new byte[] { 34, 0, 136, 0 });
new Bgra4444(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); new Bgra4444(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 136, 0, 34 }); Assert.Equal(bgr, new byte[] { 136, 0, 34 });
new Bgra4444(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Bgra4444(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 136, 0, 34, 0 }); Assert.Equal(bgra, new byte[] { 136, 0, 34, 0 });
} }
@ -236,16 +235,16 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Bgra5551(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); new Bgra5551(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 24, 0, 131 }); Assert.Equal(rgb, new byte[] { 24, 0, 131 });
new Bgra5551(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); new Bgra5551(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 24, 0, 131, 0 }); Assert.Equal(rgba, new byte[] { 24, 0, 131, 0 });
new Bgra5551(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); new Bgra5551(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 131, 0, 24 }); Assert.Equal(bgr, new byte[] { 131, 0, 24 });
new Bgra5551(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Bgra5551(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 131, 0, 24, 0 }); Assert.Equal(bgra, new byte[] { 131, 0, 24, 0 });
} }
@ -287,21 +286,21 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Byte4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); new Byte4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 128, 0, 0 }); Assert.Equal(rgb, new byte[] { 128, 0, 0 });
new Byte4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); new Byte4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 128, 0, 0, 0 }); Assert.Equal(rgba, new byte[] { 128, 0, 0, 0 });
new Byte4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); new Byte4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 0, 128 }); Assert.Equal(bgr, new byte[] { 0, 0, 128 });
new Byte4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Byte4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 0, 128, 0 }); Assert.Equal(bgra, new byte[] { 0, 0, 128, 0 });
Byte4 r = new Byte4(); Byte4 r = new Byte4();
r.PackFromBytes(20, 38, 0, 255); r.PackFromBytes(20, 38, 0, 255);
r.ToBytes(rgba, 0, ComponentOrder.XYZW); r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 }); Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 });
} }
@ -326,16 +325,16 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new HalfSingle(x).ToBytes(rgb, 0, ComponentOrder.XYZ); new HalfSingle(x).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 128, 0, 0 }); Assert.Equal(rgb, new byte[] { 128, 0, 0 });
new HalfSingle(x).ToBytes(rgba, 0, ComponentOrder.XYZW); new HalfSingle(x).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 128, 0, 0, 255 }); Assert.Equal(rgba, new byte[] { 128, 0, 0, 255 });
new HalfSingle(x).ToBytes(bgr, 0, ComponentOrder.ZYX); new HalfSingle(x).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 0, 128 }); Assert.Equal(bgr, new byte[] { 0, 0, 128 });
new HalfSingle(x).ToBytes(bgra, 0, ComponentOrder.ZYXW); new HalfSingle(x).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 0, 128, 255 }); Assert.Equal(bgra, new byte[] { 0, 0, 128, 255 });
} }
@ -363,16 +362,16 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new HalfVector2(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); new HalfVector2(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 128, 64, 0 }); Assert.Equal(rgb, new byte[] { 128, 64, 0 });
new HalfVector2(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); new HalfVector2(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 128, 64, 0, 255 }); Assert.Equal(rgba, new byte[] { 128, 64, 0, 255 });
new HalfVector2(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); new HalfVector2(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 64, 128 }); Assert.Equal(bgr, new byte[] { 0, 64, 128 });
new HalfVector2(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); new HalfVector2(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 64, 128, 255 }); Assert.Equal(bgra, new byte[] { 0, 64, 128, 255 });
} }
@ -409,16 +408,16 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new HalfVector4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); new HalfVector4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 64, 128, 191 }); Assert.Equal(rgb, new byte[] { 64, 128, 191 });
new HalfVector4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); new HalfVector4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 64, 128, 191, 255 }); Assert.Equal(rgba, new byte[] { 64, 128, 191, 255 });
new HalfVector4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); new HalfVector4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 191, 128, 64 }); Assert.Equal(bgr, new byte[] { 191, 128, 64 });
new HalfVector4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); new HalfVector4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 191, 128, 64, 255 }); Assert.Equal(bgra, new byte[] { 191, 128, 64, 255 });
} }
@ -454,16 +453,16 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new NormalizedByte2(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); new NormalizedByte2(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 0 }); Assert.Equal(rgb, new byte[] { 141, 90, 0 });
new NormalizedByte2(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); new NormalizedByte2(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 141, 90, 0, 255 }); Assert.Equal(rgba, new byte[] { 141, 90, 0, 255 });
new NormalizedByte2(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); new NormalizedByte2(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 90, 141 }); Assert.Equal(bgr, new byte[] { 0, 90, 141 });
new NormalizedByte2(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); new NormalizedByte2(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 90, 141, 255 }); Assert.Equal(bgra, new byte[] { 0, 90, 141, 255 });
} }
@ -499,26 +498,26 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new NormalizedByte4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); new NormalizedByte4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 192 }); Assert.Equal(rgb, new byte[] { 141, 90, 192 });
new NormalizedByte4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); new NormalizedByte4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 141, 90, 192, 39 }); Assert.Equal(rgba, new byte[] { 141, 90, 192, 39 });
new NormalizedByte4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); new NormalizedByte4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 192, 90, 141 }); Assert.Equal(bgr, new byte[] { 192, 90, 141 });
new NormalizedByte4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); new NormalizedByte4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 192, 90, 141, 39 }); Assert.Equal(bgra, new byte[] { 192, 90, 141, 39 });
// http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8
NormalizedByte4 r = new NormalizedByte4(); NormalizedByte4 r = new NormalizedByte4();
r.PackFromBytes(9, 115, 202, 127); r.PackFromBytes(9, 115, 202, 127);
r.ToBytes(rgba, 0, ComponentOrder.XYZW); r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 }); Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 });
r.PackedValue = 0xff4af389; r.PackedValue = 0xff4af389;
r.ToBytes(rgba, 0, ComponentOrder.XYZW); r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 }); Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 });
} }
@ -553,22 +552,22 @@ namespace ImageSharp.Tests.Colors
NormalizedShort2 n = new NormalizedShort2(); NormalizedShort2 n = new NormalizedShort2();
n.PackFromBytes(141, 90, 0, 0); n.PackFromBytes(141, 90, 0, 0);
n.ToBytes(rgb, 0, ComponentOrder.XYZ); n.ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 0 }); Assert.Equal(rgb, new byte[] { 141, 90, 0 });
// TODO: I don't think this can ever pass since the bytes are already truncated. // TODO: I don't think this can ever pass since the bytes are already truncated.
// Assert.Equal(3650751693, n.PackedValue); // Assert.Equal(3650751693, n.PackedValue);
new NormalizedShort2(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); new NormalizedShort2(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 0 }); Assert.Equal(rgb, new byte[] { 141, 90, 0 });
new NormalizedShort2(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); new NormalizedShort2(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 141, 90, 0, 255 }); Assert.Equal(rgba, new byte[] { 141, 90, 0, 255 });
new NormalizedShort2(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); new NormalizedShort2(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 90, 141 }); Assert.Equal(bgr, new byte[] { 0, 90, 141 });
new NormalizedShort2(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); new NormalizedShort2(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 90, 141, 255 }); Assert.Equal(bgra, new byte[] { 0, 90, 141, 255 });
} }
@ -600,21 +599,21 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new NormalizedShort4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); new NormalizedShort4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 141, 90, 192 }); Assert.Equal(rgb, new byte[] { 141, 90, 192 });
new NormalizedShort4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); new NormalizedShort4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 141, 90, 192, 39 }); Assert.Equal(rgba, new byte[] { 141, 90, 192, 39 });
new NormalizedShort4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); new NormalizedShort4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 192, 90, 141 }); Assert.Equal(bgr, new byte[] { 192, 90, 141 });
new NormalizedShort4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); new NormalizedShort4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 192, 90, 141, 39 }); Assert.Equal(bgra, new byte[] { 192, 90, 141, 39 });
NormalizedShort4 r = new NormalizedShort4(); NormalizedShort4 r = new NormalizedShort4();
r.PackFromBytes(9, 115, 202, 127); r.PackFromBytes(9, 115, 202, 127);
r.ToBytes(rgba, 0, ComponentOrder.XYZW); r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 }); Assert.Equal(rgba, new byte[] { 9, 115, 202, 127 });
} }
@ -647,16 +646,16 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Rg32(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); new Rg32(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 25, 0, 0 }); Assert.Equal(rgb, new byte[] { 25, 0, 0 });
new Rg32(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); new Rg32(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 25, 0, 0, 255 }); Assert.Equal(rgba, new byte[] { 25, 0, 0, 255 });
new Rg32(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); new Rg32(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 0, 25 }); Assert.Equal(bgr, new byte[] { 0, 0, 25 });
new Rg32(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Rg32(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 0, 25, 255 }); Assert.Equal(bgra, new byte[] { 0, 0, 25, 255 });
} }
@ -692,22 +691,22 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Rgba1010102(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); new Rgba1010102(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 25, 0, 128 }); Assert.Equal(rgb, new byte[] { 25, 0, 128 });
new Rgba1010102(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); new Rgba1010102(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 }); Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 });
new Rgba1010102(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); new Rgba1010102(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 128, 0, 25 }); Assert.Equal(bgr, new byte[] { 128, 0, 25 });
new Rgba1010102(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Rgba1010102(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 128, 0, 25, 0 }); Assert.Equal(bgra, new byte[] { 128, 0, 25, 0 });
// Alpha component accuracy will be awful. // Alpha component accuracy will be awful.
Rgba1010102 r = new Rgba1010102(); Rgba1010102 r = new Rgba1010102();
r.PackFromBytes(25, 0, 128, 0); r.PackFromBytes(25, 0, 128, 0);
r.ToBytes(rgba, 0, ComponentOrder.XYZW); r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 }); Assert.Equal(rgba, new byte[] { 25, 0, 128, 0 });
} }
@ -741,21 +740,21 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Rgba64(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); new Rgba64(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 20, 38, 76 }); Assert.Equal(rgb, new byte[] { 20, 38, 76 });
new Rgba64(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); new Rgba64(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 76, 115 }); Assert.Equal(rgba, new byte[] { 20, 38, 76, 115 });
new Rgba64(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); new Rgba64(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 76, 38, 20 }); Assert.Equal(bgr, new byte[] { 76, 38, 20 });
new Rgba64(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Rgba64(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 76, 38, 20, 115 }); Assert.Equal(bgra, new byte[] { 76, 38, 20, 115 });
Rgba64 r = new Rgba64(); Rgba64 r = new Rgba64();
r.PackFromBytes(20, 38, 76, 115); r.PackFromBytes(20, 38, 76, 115);
r.ToBytes(rgba, 0, ComponentOrder.XYZW); r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 76, 115 }); Assert.Equal(rgba, new byte[] { 20, 38, 76, 115 });
} }
@ -796,21 +795,21 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Short2(x, y).ToBytes(rgb, 0, ComponentOrder.XYZ); new Short2(x, y).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 128, 127, 0 }); Assert.Equal(rgb, new byte[] { 128, 127, 0 });
new Short2(x, y).ToBytes(rgba, 0, ComponentOrder.XYZW); new Short2(x, y).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 128, 127, 0, 255 }); Assert.Equal(rgba, new byte[] { 128, 127, 0, 255 });
new Short2(x, y).ToBytes(bgr, 0, ComponentOrder.ZYX); new Short2(x, y).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 0, 127, 128 }); Assert.Equal(bgr, new byte[] { 0, 127, 128 });
new Short2(x, y).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Short2(x, y).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 0, 127, 128, 255 }); Assert.Equal(bgra, new byte[] { 0, 127, 128, 255 });
Short2 r = new Short2(); Short2 r = new Short2();
r.PackFromBytes(20, 38, 0, 255); r.PackFromBytes(20, 38, 0, 255);
r.ToBytes(rgba, 0, ComponentOrder.XYZW); r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 }); Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 });
} }
@ -853,21 +852,21 @@ namespace ImageSharp.Tests.Colors
byte[] bgr = new byte[3]; byte[] bgr = new byte[3];
byte[] bgra = new byte[4]; byte[] bgra = new byte[4];
new Short4(x, y, z, w).ToBytes(rgb, 0, ComponentOrder.XYZ); new Short4(x, y, z, w).ToXyzBytes(rgb, 0);
Assert.Equal(rgb, new byte[] { 172, 177, 243 }); Assert.Equal(rgb, new byte[] { 172, 177, 243 });
new Short4(x, y, z, w).ToBytes(rgba, 0, ComponentOrder.XYZW); new Short4(x, y, z, w).ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 172, 177, 243, 128 }); Assert.Equal(rgba, new byte[] { 172, 177, 243, 128 });
new Short4(x, y, z, w).ToBytes(bgr, 0, ComponentOrder.ZYX); new Short4(x, y, z, w).ToZyxBytes(bgr, 0);
Assert.Equal(bgr, new byte[] { 243, 177, 172 }); Assert.Equal(bgr, new byte[] { 243, 177, 172 });
new Short4(x, y, z, w).ToBytes(bgra, 0, ComponentOrder.ZYXW); new Short4(x, y, z, w).ToZyxwBytes(bgra, 0);
Assert.Equal(bgra, new byte[] { 243, 177, 172, 128 }); Assert.Equal(bgra, new byte[] { 243, 177, 172, 128 });
Short4 r = new Short4(); Short4 r = new Short4();
r.PackFromBytes(20, 38, 0, 255); r.PackFromBytes(20, 38, 0, 255);
r.ToBytes(rgba, 0, ComponentOrder.XYZW); r.ToXyzwBytes(rgba, 0);
Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 }); Assert.Equal(rgba, new byte[] { 20, 38, 0, 255 });
} }

18
tests/ImageSharp.Tests/Common/ConstantsTests.cs

@ -0,0 +1,18 @@
// <copyright file="ConstantsTests.cs" company="James Jackson-South">
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
// </copyright>
namespace ImageSharp.Tests.Common
{
using Xunit;
public class ConstantsTests
{
[Fact]
public void Epsilon()
{
Assert.Equal(Constants.Epsilon, 0.001f);
}
}
}

4
tests/ImageSharp.Tests/Formats/Jpg/JpegTests.cs

@ -146,7 +146,7 @@ namespace ImageSharp.Tests
{ {
var src = provider.GetImage(); var src = provider.GetImage();
PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.XYZ); PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.Xyz);
var dest = provider.Factory.CreateImage(8, 8); var dest = provider.Factory.CreateImage(8, 8);
using (var s = src.Lock()) using (var s = src.Lock())
@ -171,7 +171,7 @@ namespace ImageSharp.Tests
{ {
var src = provider.GetImage(); var src = provider.GetImage();
PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.XYZ); PixelArea<TColor> area = new PixelArea<TColor>(8, 8, ComponentOrder.Xyz);
var dest = provider.Factory.CreateImage(8, 8); var dest = provider.Factory.CreateImage(8, 8);
using (var s = src.Lock()) using (var s = src.Lock())

6
tests/ImageSharp.Tests/Formats/Jpg/ReferenceImplementations.cs

@ -362,11 +362,11 @@ namespace ImageSharp.Tests
float a0, a1, a2, a3, b0, b1, b2, b3; float a0, a1, a2, a3, b0, b1, b2, b3;
float z0, z1, z2, z3, z4; float z0, z1, z2, z3, z4;
float r0 = 1.414214f; //float r0 = 1.414214f;
float r1 = 1.387040f; float r1 = 1.387040f;
float r2 = 1.306563f; float r2 = 1.306563f;
float r3 = 1.175876f; float r3 = 1.175876f;
float r4 = 1.000000f; //float r4 = 1.000000f;
float r5 = 0.785695f; float r5 = 0.785695f;
float r6 = 0.541196f; float r6 = 0.541196f;
float r7 = 0.275899f; float r7 = 0.275899f;
@ -794,7 +794,7 @@ namespace ImageSharp.Tests
r[7] = 0.275899f; r[7] = 0.275899f;
const float invsqrt2 = 0.707107f; //(float)(1.0f / M_SQRT2); const float invsqrt2 = 0.707107f; //(float)(1.0f / M_SQRT2);
const float invsqrt2h = 0.353554f; //invsqrt2*0.5f; //const float invsqrt2h = 0.353554f; //invsqrt2*0.5f;
c1 = x[0]; c1 = x[0];
c2 = x[7]; c2 = x[7];

24
tests/ImageSharp.Tests/Image/PixelAccessorTests.cs

@ -40,10 +40,10 @@ namespace ImageSharp.Tests
} }
[Theory] [Theory]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.XYZ)] [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.Xyz)]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.ZYX)] [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.Zyx)]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.XYZW)] [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.Xyzw)]
[WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.ZYXW)] [WithMemberFactory(nameof(CreateTestImage), PixelTypes.All, ComponentOrder.Zyxw)]
public void CopyTo_Then_CopyFrom_OnFullImageRect<TColor>(TestImageProvider<TColor> provider, ComponentOrder order) public void CopyTo_Then_CopyFrom_OnFullImageRect<TColor>(TestImageProvider<TColor> provider, ComponentOrder order)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
@ -84,10 +84,10 @@ namespace ImageSharp.Tests
} }
[Theory] [Theory]
[WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.XYZ)] [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.Xyz)]
[WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.ZYX)] [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.Zyx)]
[WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.XYZW)] [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.Xyzw)]
[WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.ZYXW)] [WithBlankImages(16, 16, PixelTypes.All, ComponentOrder.Zyxw)]
public void CopyTo_Then_CopyFrom_WithOffset<TColor>(TestImageProvider<TColor> provider, ComponentOrder order) public void CopyTo_Then_CopyFrom_WithOffset<TColor>(TestImageProvider<TColor> provider, ComponentOrder order)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
@ -181,7 +181,7 @@ namespace ImageSharp.Tests
byte blue = 3; byte blue = 3;
byte alpha = 255; byte alpha = 255;
using (PixelArea<TColor> row = new PixelArea<TColor>(1, ComponentOrder.ZYX)) using (PixelArea<TColor> row = new PixelArea<TColor>(1, ComponentOrder.Zyx))
{ {
row.Bytes[0] = blue; row.Bytes[0] = blue;
row.Bytes[1] = green; row.Bytes[1] = green;
@ -208,7 +208,7 @@ namespace ImageSharp.Tests
byte blue = 3; byte blue = 3;
byte alpha = 4; byte alpha = 4;
using (PixelArea<TColor> row = new PixelArea<TColor>(1, ComponentOrder.ZYXW)) using (PixelArea<TColor> row = new PixelArea<TColor>(1, ComponentOrder.Zyxw))
{ {
row.Bytes[0] = blue; row.Bytes[0] = blue;
row.Bytes[1] = green; row.Bytes[1] = green;
@ -235,7 +235,7 @@ namespace ImageSharp.Tests
byte green = 2; byte green = 2;
byte blue = 3; byte blue = 3;
using (PixelArea<TColor> row = new PixelArea<TColor>(1, ComponentOrder.ZYX)) using (PixelArea<TColor> row = new PixelArea<TColor>(1, ComponentOrder.Zyx))
{ {
pixels[0, 0] = (TColor)(object)new Color(red, green, blue); pixels[0, 0] = (TColor)(object)new Color(red, green, blue);
@ -258,7 +258,7 @@ namespace ImageSharp.Tests
byte blue = 3; byte blue = 3;
byte alpha = 4; byte alpha = 4;
using (PixelArea<TColor> row = new PixelArea<TColor>(1, ComponentOrder.ZYXW)) using (PixelArea<TColor> row = new PixelArea<TColor>(1, ComponentOrder.Zyxw))
{ {
pixels[0, 0] = (TColor)(object)new Color(red, green, blue, alpha); pixels[0, 0] = (TColor)(object)new Color(red, green, blue, alpha);

12
tests/ImageSharp.Tests/TestUtilities/TestUtilityExtensions.cs

@ -21,7 +21,7 @@ namespace ImageSharp.Tests
private static readonly Assembly ImageSharpAssembly = typeof(Color).GetTypeInfo().Assembly; private static readonly Assembly ImageSharpAssembly = typeof(Color).GetTypeInfo().Assembly;
private static readonly Dictionary<PixelTypes, Type> PixelTypes2ClrTypes = new Dictionary<PixelTypes, Type>(); private static readonly Dictionary<PixelTypes, Type> PixelTypes2ClrTypes = new Dictionary<PixelTypes, Type>();
private static readonly PixelTypes[] AllConcretePixelTypes = EnumHelper.GetSortedValues<PixelTypes>() private static readonly PixelTypes[] AllConcretePixelTypes = EnumHelper.GetSortedValues<PixelTypes>()
.Except(new [] {PixelTypes.Undefined, PixelTypes.All }) .Except(new [] {PixelTypes.Undefined, PixelTypes.All })
.ToArray(); .ToArray();
@ -53,7 +53,7 @@ namespace ImageSharp.Tests
return intrfcType.GetGenericArguments().Single(); return intrfcType.GetGenericArguments().Single();
} }
public static bool HasFlag(this PixelTypes pixelTypes, PixelTypes flag) => (pixelTypes & flag) == flag; public static bool HasFlag(this PixelTypes pixelTypes, PixelTypes flag) => (pixelTypes & flag) == flag;
public static bool IsEquivalentTo<TColor>(this Image<TColor> a, Image<TColor> b, bool compareAlpha = true) public static bool IsEquivalentTo<TColor>(this Image<TColor> a, Image<TColor> b, bool compareAlpha = true)
@ -87,11 +87,11 @@ namespace ImageSharp.Tests
} }
else else
{ {
ca.ToBytes(bytesA, 0, ComponentOrder.XYZ); ca.ToXyzBytes(bytesA, 0);
cb.ToBytes(bytesB, 0, ComponentOrder.XYZ); cb.ToXyzBytes(bytesB, 0);
if (bytesA[0] != bytesB[0] || if (bytesA[0] != bytesB[0] ||
bytesA[1] != bytesB[1] || bytesA[1] != bytesB[1] ||
bytesA[2] != bytesB[2]) bytesA[2] != bytesB[2])
{ {
return false; return false;

8
tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs

@ -35,7 +35,7 @@ namespace ImageSharp.Tests
[WithBlankImages(42, 666, PixelTypes.All, "hello")] [WithBlankImages(42, 666, PixelTypes.All, "hello")]
public void Use_WithBlankImagesAttribute_WithAllPixelTypes<TColor>( public void Use_WithBlankImagesAttribute_WithAllPixelTypes<TColor>(
TestImageProvider<TColor> provider, TestImageProvider<TColor> provider,
string message) string message)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
var img = provider.GetImage(); var img = provider.GetImage();
@ -59,7 +59,7 @@ namespace ImageSharp.Tests
[WithBlankImages(1, 1, PixelTypes.StandardImageClass)] [WithBlankImages(1, 1, PixelTypes.StandardImageClass)]
[WithFile(TestImages.Bmp.F, PixelTypes.StandardImageClass)] [WithFile(TestImages.Bmp.F, PixelTypes.StandardImageClass)]
public void PixelTypes_ColorWithDefaultImageClass_TriggersCreatingTheNonGenericDerivedImageClass<TColor>( public void PixelTypes_ColorWithDefaultImageClass_TriggersCreatingTheNonGenericDerivedImageClass<TColor>(
TestImageProvider<TColor> provider) TestImageProvider<TColor> provider)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
var img = provider.GetImage(); var img = provider.GetImage();
@ -112,7 +112,7 @@ namespace ImageSharp.Tests
{ {
for (int x = 0; x < pixels.Width; x++) for (int x = 0; x < pixels.Width; x++)
{ {
pixels[x, y].ToBytes(colors, 0, ComponentOrder.XYZW); pixels[x, y].ToXyzwBytes(colors, 0);
Assert.Equal(colors[0], 255); Assert.Equal(colors[0], 255);
Assert.Equal(colors[1], 100); Assert.Equal(colors[1], 100);
@ -129,7 +129,7 @@ namespace ImageSharp.Tests
/// <typeparam name="TColor"></typeparam> /// <typeparam name="TColor"></typeparam>
/// <param name="factory"></param> /// <param name="factory"></param>
/// <returns></returns> /// <returns></returns>
public static Image<TColor> CreateTestImage<TColor>(GenericFactory<TColor> factory) public static Image<TColor> CreateTestImage<TColor>(GenericFactory<TColor> factory)
where TColor : struct, IPackedPixel, IEquatable<TColor> where TColor : struct, IPackedPixel, IEquatable<TColor>
{ {
return factory.CreateImage(3, 3); return factory.CreateImage(3, 3);

7
tests/ImageSharp.Tests/project.json

@ -12,6 +12,13 @@
"buildOptions": { "buildOptions": {
"allowUnsafe": true "allowUnsafe": true
}, },
"configurations": {
"Release": {
"buildOptions": {
"warningsAsErrors": true
}
}
},
"dependencies": { "dependencies": {
"ImageSharp": "1.0.0-*", "ImageSharp": "1.0.0-*",
"xunit": "2.2.0-*", "xunit": "2.2.0-*",

Loading…
Cancel
Save