Browse Source

Merge branch 'master' into master

pull/725/head
SimantoR 8 years ago
committed by GitHub
parent
commit
1e7dc83cfe
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 22
      README.md
  2. 4
      src/ImageSharp.Drawing/ImageSharp.Drawing.csproj
  3. 2
      src/ImageSharp/ColorSpaces/CieLab.cs
  4. 2
      src/ImageSharp/ColorSpaces/CieLch.cs
  5. 2
      src/ImageSharp/ColorSpaces/CieLchuv.cs
  6. 2
      src/ImageSharp/ColorSpaces/CieLuv.cs
  7. 2
      src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs
  8. 2
      src/ImageSharp/ColorSpaces/CieXyy.cs
  9. 2
      src/ImageSharp/ColorSpaces/CieXyz.cs
  10. 2
      src/ImageSharp/ColorSpaces/Cmyk.cs
  11. 2
      src/ImageSharp/ColorSpaces/Hsl.cs
  12. 2
      src/ImageSharp/ColorSpaces/Hsv.cs
  13. 2
      src/ImageSharp/ColorSpaces/HunterLab.cs
  14. 2
      src/ImageSharp/ColorSpaces/LinearRgb.cs
  15. 2
      src/ImageSharp/ColorSpaces/Lms.cs
  16. 2
      src/ImageSharp/ColorSpaces/Rgb.cs
  17. 2
      src/ImageSharp/ColorSpaces/YCbCr.cs
  18. 4
      src/ImageSharp/Common/Extensions/EncoderExtensions.cs
  19. 232
      src/ImageSharp/Common/Extensions/SimdUtils.cs
  20. 107
      src/ImageSharp/Common/Helpers/ImageMaths.cs
  21. 215
      src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs
  22. 178
      src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs
  23. 151
      src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs
  24. 185
      src/ImageSharp/Common/Helpers/SimdUtils.cs
  25. 4
      src/ImageSharp/Common/Helpers/TestHelpers.cs
  26. 109
      src/ImageSharp/Common/Tuples/Octet.cs
  27. 12
      src/ImageSharp/Common/Tuples/Vector4Pair.cs
  28. 8
      src/ImageSharp/Configuration.cs
  29. 24
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  30. 4
      src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs
  31. 6
      src/ImageSharp/Formats/Gif/GifConstants.cs
  32. 34
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  33. 34
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  34. 4
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs
  35. 4
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs
  36. 6
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
  37. 8
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs
  38. 2
      src/ImageSharp/Formats/Png/PngConstants.cs
  39. 2
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  40. 116
      src/ImageSharp/Formats/Png/PngEncoderCore.cs
  41. 57
      src/ImageSharp/Formats/Png/PngScanlineProcessor.cs
  42. 2
      src/ImageSharp/IO/IFileSystem.cs
  43. 17
      src/ImageSharp/IO/LocalFileSystem.cs
  44. 3
      src/ImageSharp/Image.FromBytes.cs
  45. 4
      src/ImageSharp/Image.FromFile.cs
  46. 3
      src/ImageSharp/ImageExtensions.cs
  47. 14
      src/ImageSharp/ImageFrame{TPixel}.cs
  48. 76
      src/ImageSharp/ImageSharp.csproj
  49. 2
      src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Primitives.cs
  50. 2
      src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs
  51. 4
      src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs
  52. 6
      src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs
  53. 9
      src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs
  54. 5
      src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs
  55. 4
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs
  56. 171
      src/ImageSharp/PixelFormats/Alpha8.cs
  57. 253
      src/ImageSharp/PixelFormats/Argb32.cs
  58. 179
      src/ImageSharp/PixelFormats/Bgr24.cs
  59. 204
      src/ImageSharp/PixelFormats/Bgr565.cs
  60. 210
      src/ImageSharp/PixelFormats/Bgra32.cs
  61. 186
      src/ImageSharp/PixelFormats/Bgra4444.cs
  62. 194
      src/ImageSharp/PixelFormats/Bgra5551.cs
  63. 168
      src/ImageSharp/PixelFormats/Byte4.cs
  64. 177
      src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs
  65. 85
      src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt
  66. 177
      src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs
  67. 85
      src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt
  68. 177
      src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs
  69. 85
      src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt
  70. 177
      src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs
  71. 85
      src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt
  72. 177
      src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs
  73. 85
      src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt
  74. 621
      src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs
  75. 92
      src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt
  76. 177
      src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs
  77. 85
      src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt
  78. 177
      src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs
  79. 85
      src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt
  80. 124
      src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs
  81. 70
      src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt
  82. 177
      src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs
  83. 85
      src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt
  84. 177
      src/ImageSharp/PixelFormats/Gray16.cs
  85. 152
      src/ImageSharp/PixelFormats/Gray8.cs
  86. 202
      src/ImageSharp/PixelFormats/HalfSingle.cs
  87. 12
      src/ImageSharp/PixelFormats/HalfTypeHelper.cs
  88. 216
      src/ImageSharp/PixelFormats/HalfVector2.cs
  89. 188
      src/ImageSharp/PixelFormats/HalfVector4.cs
  90. 78
      src/ImageSharp/PixelFormats/IPixel.cs
  91. 253
      src/ImageSharp/PixelFormats/NormalizedByte2.cs
  92. 234
      src/ImageSharp/PixelFormats/NormalizedByte4.cs
  93. 239
      src/ImageSharp/PixelFormats/NormalizedShort2.cs
  94. 243
      src/ImageSharp/PixelFormats/NormalizedShort4.cs
  95. 54
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs
  96. 216
      src/ImageSharp/PixelFormats/Rg32.cs
  97. 186
      src/ImageSharp/PixelFormats/Rgb24.cs
  98. 189
      src/ImageSharp/PixelFormats/Rgb48.cs
  99. 208
      src/ImageSharp/PixelFormats/Rgba1010102.cs
  100. 160
      src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs

22
README.md

@ -22,7 +22,7 @@ Designed to democratize image processing, ImageSharp brings you an incredibly po
Compared to `System.Drawing` we have been able to develop something much more flexible, easier to code against, and much, much less prone to memory leaks. Gone are system-wide process-locks; ImageSharp images are thread-safe and fully supported in web environments. Compared to `System.Drawing` we have been able to develop something much more flexible, easier to code against, and much, much less prone to memory leaks. Gone are system-wide process-locks; ImageSharp images are thread-safe and fully supported in web environments.
Built against .Net Standard 1.1 ImageSharp can be used in device, cloud, and embedded/IoT scenarios. Built against .NET Standard 1.3 ImageSharp can be used in device, cloud, and embedded/IoT scenarios.
### Documentation ### Documentation
For all SixLabors projects, including ImageSharp: For all SixLabors projects, including ImageSharp:
@ -83,24 +83,6 @@ using (Image<Rgba32> image = Image.Load("foo.jpg"))
image.Save("bar.jpg"); // Automatic encoder selected based on extension. image.Save("bar.jpg"); // Automatic encoder selected based on extension.
} }
``` ```
On netstandard 1.1 - 1.2
```csharp
using SixLabors.ImageSharp;
using SixLabors.ImageSharp.Processing;
// Image.Load(Stream stream) is a shortcut for our default type.
// Other pixel formats use Image.Load<TPixel>(Stream stream))
using (FileStream stream = File.OpenRead("foo.jpg"))
using (FileStream output = File.OpenWrite("bar.jpg"))
using (Image<Rgba32> image = Image.Load(stream))
{
image.Mutate(x => x
.Resize(image.Width / 2, image.Height / 2)
.Grayscale());
image.Save(output);
}
```
Setting individual pixel values can be performed as follows: Setting individual pixel values can be performed as follows:
@ -133,7 +115,7 @@ If you prefer, you can compile ImageSharp yourself (please do and help!)
Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**: Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**:
- [Visual Studio Code](https://code.visualstudio.com/) with [C# Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp) - [Visual Studio Code](https://code.visualstudio.com/) with [C# Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp)
- [.Net Core](https://www.microsoft.com/net/core#linuxubuntu) - [.NET Core](https://www.microsoft.com/net/core#linuxubuntu)
To clone ImageSharp locally click the "Clone in Windows" button above or run the following git commands. To clone ImageSharp locally click the "Clone in Windows" button above or run the following git commands.

4
src/ImageSharp.Drawing/ImageSharp.Drawing.csproj

@ -5,8 +5,8 @@
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix> <VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix> <VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<Authors>SixLabors and contributors</Authors> <Authors>SixLabors and contributors</Authors>
<TargetFrameworks>netstandard1.1;netstandard2.0</TargetFrameworks> <TargetFrameworks>netstandard1.3;netstandard2.0</TargetFrameworks>
<LangVersion>7.2</LangVersion> <LangVersion>7.3</LangVersion>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName> <AssemblyName>SixLabors.ImageSharp.Drawing</AssemblyName>

2
src/ImageSharp/ColorSpaces/CieLab.cs

@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"; public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is CieLab other && this.Equals(other); public override bool Equals(object obj) => obj is CieLab other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/CieLch.cs

@ -129,7 +129,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"; public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]

2
src/ImageSharp/ColorSpaces/CieLchuv.cs

@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"; public override string ToString() => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other); public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/CieLuv.cs

@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})"; public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other); public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs

@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode()); public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode());
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"CieXyChromaticityCoordinates({this.X:#0.##}, {this.Y:#0.##})"; public override string ToString() => FormattableString.Invariant($"CieXyChromaticityCoordinates({this.X:#0.##}, {this.Y:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other); public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/CieXyy.cs

@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})"; public override string ToString() => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is CieXyy other && this.Equals(other); public override bool Equals(object obj) => obj is CieXyy other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/CieXyz.cs

@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})"; public override string ToString() => FormattableString.Invariant($"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other); public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/Cmyk.cs

@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})"; public override string ToString() => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other); public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/Hsl.cs

@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})"; public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is Hsl other && this.Equals(other); public override bool Equals(object obj) => obj is Hsl other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/Hsv.cs

@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})"; public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is Hsv other && this.Equals(other); public override bool Equals(object obj) => obj is Hsv other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/HunterLab.cs

@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"; public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other); public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/LinearRgb.cs

@ -134,7 +134,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"LinearRgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"; public override string ToString() => FormattableString.Invariant($"LinearRgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other); public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/Lms.cs

@ -95,7 +95,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"Lms({this.L:#0.##}, {this.M:#0.##}, {this.S:#0.##})"; public override string ToString() => FormattableString.Invariant($"Lms({this.L:#0.##}, {this.M:#0.##}, {this.S:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is Lms other && this.Equals(other); public override bool Equals(object obj) => obj is Lms other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/Rgb.cs

@ -155,7 +155,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"; public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is Rgb other && this.Equals(other); public override bool Equals(object obj) => obj is Rgb other && this.Equals(other);

2
src/ImageSharp/ColorSpaces/YCbCr.cs

@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.ColorSpaces
} }
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() => $"YCbCr({this.Y}, {this.Cb}, {this.Cr})"; public override string ToString() => FormattableString.Invariant($"YCbCr({this.Y}, {this.Cb}, {this.Cr})");
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other); public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other);

4
src/ImageSharp/Common/Extensions/EncoderExtensions.cs

@ -20,14 +20,10 @@ namespace SixLabors.ImageSharp
/// <returns>The string.</returns> /// <returns>The string.</returns>
public static string GetString(this Encoding encoding, ReadOnlySpan<byte> buffer) public static string GetString(this Encoding encoding, ReadOnlySpan<byte> buffer)
{ {
#if NETSTANDARD1_1
return encoding.GetString(buffer.ToArray());
#else
fixed (byte* bytes = buffer) fixed (byte* bytes = buffer)
{ {
return encoding.GetString(bytes, buffer.Length); return encoding.GetString(bytes, buffer.Length);
} }
#endif
} }
} }
} }

232
src/ImageSharp/Common/Extensions/SimdUtils.cs

@ -1,232 +0,0 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Various extension and utility methods for <see cref="Vector4"/> and <see cref="Vector{T}"/> utilizing SIMD capabilities
/// </summary>
internal static class SimdUtils
{
/// <summary>
/// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte.
/// </summary>
public static bool IsAvx2CompatibleArchitecture => Vector<float>.Count == 8 && Vector<int>.Count == 8;
internal static void GuardAvx2(string operation)
{
if (!IsAvx2CompatibleArchitecture)
{
throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!");
}
}
/// <summary>
/// Transform all scalars in 'v' in a way that converting them to <see cref="int"/> would have rounding semantics.
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector4 PseudoRound(this Vector4 v)
{
var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1));
return v + (sign * 0.5f);
}
/// <summary>
/// Rounds all values in 'v' to the nearest integer following <see cref="MidpointRounding.ToEven"/> semantics.
/// Source:
/// <see>
/// <cref>https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110</cref>
/// </see>
/// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector<float> FastRound(this Vector<float> x)
{
Vector<int> magic0 = new Vector<int>(int.MinValue); // 0x80000000
Vector<float> sgn0 = Vector.AsVectorSingle(magic0);
Vector<float> and0 = Vector.BitwiseAnd(sgn0, x);
Vector<float> or0 = Vector.BitwiseOr(and0, new Vector<float>(8388608.0f));
Vector<float> add0 = Vector.Add(x, or0);
Vector<float> sub0 = Vector.Subtract(add0, or0);
return sub0;
}
/// <summary>
/// Convert 'source.Length' <see cref="float"/> values normalized into [0..1] from 'source' into 'dest' buffer of <see cref="byte"/> values.
/// The values gonna be scaled up into [0-255] and rounded.
/// Based on:
/// <see>
/// <cref>http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions</cref>
/// </see>
/// </summary>
internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan<float> source, Span<byte> dest)
{
GuardAvx2(nameof(BulkConvertNormalizedFloatToByte));
DebugGuard.IsTrue((source.Length % Vector<float>.Count) == 0, nameof(source), "source.Length should be divisable by Vector<float>.Count!");
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
Vector<float> magick = new Vector<float>(32768.0f);
Vector<float> scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
/// <summary>
/// Same as <see cref="BulkConvertNormalizedFloatToByte"/> but clamps overflown values before conversion.
/// </summary>
internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan<float> source, Span<byte> dest)
{
GuardAvx2(nameof(BulkConvertNormalizedFloatToByte));
DebugGuard.IsTrue((source.Length % Vector<float>.Count) == 0, nameof(source), "source.Length should be divisable by Vector<float>.Count!");
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
Vector<float> magick = new Vector<float>(32768.0f);
Vector<float> scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = Vector.Max(x, Vector<float>.Zero);
x = Vector.Min(x, Vector<float>.One);
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
// TODO: Replace these with T4-d library level tuples!
internal static class Octet
{
[StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))]
public struct OfUInt32
{
[FieldOffset(0 * sizeof(uint))]
public uint V0;
[FieldOffset(1 * sizeof(uint))]
public uint V1;
[FieldOffset(2 * sizeof(uint))]
public uint V2;
[FieldOffset(3 * sizeof(uint))]
public uint V3;
[FieldOffset(4 * sizeof(uint))]
public uint V4;
[FieldOffset(5 * sizeof(uint))]
public uint V5;
[FieldOffset(6 * sizeof(uint))]
public uint V6;
[FieldOffset(7 * sizeof(uint))]
public uint V7;
public override string ToString()
{
return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]";
}
}
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct OfByte
{
[FieldOffset(0)]
public byte V0;
[FieldOffset(1)]
public byte V1;
[FieldOffset(2)]
public byte V2;
[FieldOffset(3)]
public byte V3;
[FieldOffset(4)]
public byte V4;
[FieldOffset(5)]
public byte V5;
[FieldOffset(6)]
public byte V6;
[FieldOffset(7)]
public byte V7;
public override string ToString()
{
return $"[{this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7}]";
}
public void LoadFrom(ref OfUInt32 i)
{
this.V0 = (byte)i.V0;
this.V1 = (byte)i.V1;
this.V2 = (byte)i.V2;
this.V3 = (byte)i.V3;
this.V4 = (byte)i.V4;
this.V5 = (byte)i.V5;
this.V6 = (byte)i.V6;
this.V7 = (byte)i.V7;
}
}
}
}
}

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

@ -14,6 +14,73 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
internal static class ImageMaths internal static class ImageMaths
{ {
/// <summary>
/// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <returns>The <see cref="byte"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F));
/// <summary>
/// Gets the luminance from the rgb components using the formula as specified by ITU-R Recommendation BT.709.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
/// <returns>The <see cref="ushort"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort Get16BitBT709Luminance(ushort r, ushort g, ushort b) => (ushort)((r * .2126F) + (g * .7152F) + (b * .0722F));
/// <summary>
/// Scales a value from a 16 bit <see cref="ushort"/> to it's 8 bit <see cref="byte"/> equivalent.
/// </summary>
/// <param name="component">The 8 bit compoonent value.</param>
/// <returns>The <see cref="byte"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static byte DownScaleFrom16BitTo8Bit(ushort component)
{
// To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is:
//
// (V * 255) / 65535
//
// This reduces to round(V / 257), or floor((V + 128.5)/257)
//
// Represent V as the two byte value vhi.vlo. Make a guess that the
// result is the top byte of V, vhi, then the correction to this value
// is:
//
// error = floor(((V-vhi.vhi) + 128.5) / 257)
// = floor(((vlo-vhi) + 128.5) / 257)
//
// This can be approximated using integer arithmetic (and a signed
// shift):
//
// error = (vlo-vhi+128) >> 8;
//
// The approximate differs from the exact answer only when (vlo-vhi) is
// 128; it then gives a correction of +1 when the exact correction is
// 0. This gives 128 errors. The exact answer (correct for all 16-bit
// input values) is:
//
// error = (vlo-vhi+128)*65535 >> 24;
//
// An alternative arithmetic calculation which also gives no errors is:
//
// (V * 255 + 32895) >> 16
return (byte)(((component * 255) + 32895) >> 16);
}
/// <summary>
/// Scales a value from an 8 bit <see cref="byte"/> to it's 16 bit <see cref="ushort"/> equivalent.
/// </summary>
/// <param name="component">The 8 bit compoonent value.</param>
/// <returns>The <see cref="ushort"/></returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static ushort UpscaleFrom8BitTo16Bit(byte component) => (ushort)(component * 257);
/// <summary> /// <summary>
/// Determine the Greatest CommonDivisor (GCD) of two numbers. /// Determine the Greatest CommonDivisor (GCD) of two numbers.
/// </summary> /// </summary>
@ -39,6 +106,28 @@ namespace SixLabors.ImageSharp
return (a / GreatestCommonDivisor(a, b)) * b; return (a / GreatestCommonDivisor(a, b)) * b;
} }
/// <summary>
/// Calculates <paramref name="x"/> % 4
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static int Modulo4(int x) => x & 3;
/// <summary>
/// Calculates <paramref name="x"/> % 8
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static int Modulo8(int x) => x & 7;
/// <summary>
/// Fast (x mod m) calculator, with the restriction that
/// <paramref name="m"/> should be power of 2.
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
public static int ModuloP2(int x, int m)
{
return x & (m - 1);
}
/// <summary> /// <summary>
/// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation.
/// </summary> /// </summary>
@ -46,7 +135,7 @@ namespace SixLabors.ImageSharp
/// A number that is greater than <see cref="int.MinValue"/>, but less than or equal to <see cref="int.MaxValue"/> /// A number that is greater than <see cref="int.MinValue"/>, but less than or equal to <see cref="int.MaxValue"/>
/// </param> /// </param>
/// <returns>The <see cref="int"/></returns> /// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static int FastAbs(int x) public static int FastAbs(int x)
{ {
int y = x >> 31; int y = x >> 31;
@ -58,7 +147,7 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
/// <param name="x">A single-precision floating-point number</param> /// <param name="x">A single-precision floating-point number</param>
/// <returns>The number <paramref name="x" /> raised to the power of 2.</returns> /// <returns>The number <paramref name="x" /> raised to the power of 2.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static float Pow2(float x) => x * x; public static float Pow2(float x) => x * x;
/// <summary> /// <summary>
@ -66,7 +155,7 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
/// <param name="x">A single-precision floating-point number</param> /// <param name="x">A single-precision floating-point number</param>
/// <returns>The number <paramref name="x" /> raised to the power of 3.</returns> /// <returns>The number <paramref name="x" /> raised to the power of 3.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static float Pow3(float x) => x * x * x; public static float Pow3(float x) => x * x * x;
/// <summary> /// <summary>
@ -77,7 +166,7 @@ namespace SixLabors.ImageSharp
/// <returns> /// <returns>
/// The <see cref="int"/> /// The <see cref="int"/>
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static int GetBitsNeededForColorDepth(int colors) => Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2))); public static int GetBitsNeededForColorDepth(int colors) => Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2)));
/// <summary> /// <summary>
@ -85,7 +174,7 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
/// <param name="bitDepth">The bit depth.</param> /// <param name="bitDepth">The bit depth.</param>
/// <returns>The <see cref="int"/></returns> /// <returns>The <see cref="int"/></returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static int GetColorCountForBitDepth(int bitDepth) => 1 << bitDepth; public static int GetColorCountForBitDepth(int bitDepth) => 1 << bitDepth;
/// <summary> /// <summary>
@ -94,7 +183,7 @@ namespace SixLabors.ImageSharp
/// <param name="x">The x provided to G(x).</param> /// <param name="x">The x provided to G(x).</param>
/// <param name="sigma">The spread of the blur.</param> /// <param name="sigma">The spread of the blur.</param>
/// <returns>The Gaussian G(x)</returns> /// <returns>The Gaussian G(x)</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static float Gaussian(float x, float sigma) public static float Gaussian(float x, float sigma)
{ {
const float Numerator = 1.0f; const float Numerator = 1.0f;
@ -117,7 +206,7 @@ namespace SixLabors.ImageSharp
/// <returns> /// <returns>
/// The sine cardinal of <paramref name="f" />. /// The sine cardinal of <paramref name="f" />.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static float SinC(float f) public static float SinC(float f)
{ {
if (MathF.Abs(f) > Constants.Epsilon) if (MathF.Abs(f) > Constants.Epsilon)
@ -140,7 +229,7 @@ namespace SixLabors.ImageSharp
/// <returns> /// <returns>
/// The <see cref="float"/>. /// The <see cref="float"/>.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static float GetBcValue(float x, float b, float c) public static float GetBcValue(float x, float b, float c)
{ {
if (x < 0F) if (x < 0F)
@ -176,7 +265,7 @@ namespace SixLabors.ImageSharp
/// <returns> /// <returns>
/// The bounding <see cref="Rectangle"/>. /// The bounding <see cref="Rectangle"/>.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) => new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) => new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y);
/// <summary> /// <summary>

215
src/ImageSharp/Common/Helpers/SimdUtils.BasicIntrinsics256.cs

@ -0,0 +1,215 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Tuples;
// ReSharper disable MemberHidesStaticFromOuterClass
namespace SixLabors.ImageSharp
{
internal static partial class SimdUtils
{
/// <summary>
/// Implementation with 256bit / AVX2 intrinsics NOT depending on newer API-s (Vector.Widen etc.)
/// </summary>
public static class BasicIntrinsics256
{
public static bool IsAvailable { get; } = IsAvx2CompatibleArchitecture;
/// <summary>
/// <see cref="BulkConvertByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertByteToNormalizedFloatReduce(
ref ReadOnlySpan<byte> source,
ref Span<float> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = ImageMaths.Modulo8(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertByteToNormalizedFloat(
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// <see cref="BulkConvertNormalizedFloatToByteClampOverflows"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce(
ref ReadOnlySpan<float> source,
ref Span<byte> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = ImageMaths.Modulo8(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertNormalizedFloatToByteClampOverflows(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// SIMD optimized implementation for <see cref="SimdUtils.BulkConvertByteToNormalizedFloat"/>.
/// Works only with span Length divisible by 8.
/// Implementation adapted from:
/// http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions
/// http://stackoverflow.com/a/536278
/// </summary>
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
VerifyIsAvx2Compatible(nameof(BulkConvertByteToNormalizedFloat));
VerifySpanInput(source, dest, 8);
var bVec = new Vector<float>(256.0f / 255.0f);
var magicFloat = new Vector<float>(32768.0f);
var magicInt = new Vector<uint>(1191182336); // reinterpreded value of 32768.0f
var mask = new Vector<uint>(255);
ref Octet.OfByte sourceBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(source));
ref Octet.OfUInt32 destBaseAsWideOctet = ref Unsafe.As<float, Octet.OfUInt32>(ref MemoryMarshal.GetReference(dest));
ref Vector<float> destBaseAsFloat = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref destBaseAsWideOctet);
int n = dest.Length / 8;
for (int i = 0; i < n; i++)
{
ref Octet.OfByte s = ref Unsafe.Add(ref sourceBase, i);
ref Octet.OfUInt32 d = ref Unsafe.Add(ref destBaseAsWideOctet, i);
d.LoadFrom(ref s);
}
for (int i = 0; i < n; i++)
{
ref Vector<float> df = ref Unsafe.Add(ref destBaseAsFloat, i);
var vi = Vector.AsVectorUInt32(df);
vi &= mask;
vi |= magicInt;
var vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
df = vf;
}
}
/// <summary>
/// Implementation of <see cref="SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows"/> which is faster on older runtimes.
/// </summary>
internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan<float> source, Span<byte> dest)
{
VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByteClampOverflows));
VerifySpanInput(source, dest, 8);
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
Vector<float> magick = new Vector<float>(32768.0f);
Vector<float> scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = Vector.Max(x, Vector<float>.Zero);
x = Vector.Min(x, Vector<float>.One);
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
/// <summary>
/// Convert all <see cref="float"/> values normalized into [0..1] from 'source'
/// into 'dest' buffer of <see cref="byte"/>. The values are scaled up into [0-255] and rounded.
/// This implementation is SIMD optimized and works only when span Length is divisible by 8.
/// Based on:
/// <see>
/// <cref>http://lolengine.net/blog/2011/3/20/understanding-fast-float-integer-conversions</cref>
/// </see>
/// </summary>
internal static void BulkConvertNormalizedFloatToByte(ReadOnlySpan<float> source, Span<byte> dest)
{
VerifyIsAvx2Compatible(nameof(BulkConvertNormalizedFloatToByte));
VerifySpanInput(source, dest, 8);
if (source.Length == 0)
{
return;
}
ref Vector<float> srcBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Octet.OfByte destBase = ref Unsafe.As<byte, Octet.OfByte>(ref MemoryMarshal.GetReference(dest));
int n = source.Length / 8;
Vector<float> magick = new Vector<float>(32768.0f);
Vector<float> scale = new Vector<float>(255f) / new Vector<float>(256f);
// need to copy to a temporary struct, because
// SimdUtils.Octet.OfUInt32 temp = Unsafe.As<Vector<float>, SimdUtils.Octet.OfUInt32>(ref x)
// does not work. TODO: This might be a CoreClr bug, need to ask/report
var temp = default(Octet.OfUInt32);
ref Vector<float> tempRef = ref Unsafe.As<Octet.OfUInt32, Vector<float>>(ref temp);
for (int i = 0; i < n; i++)
{
// union { float f; uint32_t i; } u;
// u.f = 32768.0f + x * (255.0f / 256.0f);
// return (uint8_t)u.i;
Vector<float> x = Unsafe.Add(ref srcBase, i);
x = (x * scale) + magick;
tempRef = x;
ref Octet.OfByte d = ref Unsafe.Add(ref destBase, i);
d.LoadFrom(ref temp);
}
}
}
}
}

178
src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs

@ -0,0 +1,178 @@
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ReSharper disable MemberHidesStaticFromOuterClass
namespace SixLabors.ImageSharp
{
internal static partial class SimdUtils
{
/// <summary>
/// Implementation methods based on newer <see cref="Vector{T}"/> API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*).
/// Only accelerated only on RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+)
/// See:
/// https://github.com/dotnet/coreclr/pull/10662
/// API Proposal:
/// https://github.com/dotnet/corefx/issues/15957
/// </summary>
public static class ExtendedIntrinsics
{
public static bool IsAvailable { get; } =
#if NETCOREAPP2_1
// TODO: Also available in .NET 4.7.2, we need to add a build target!
Vector.IsHardwareAccelerated;
#else
false;
#endif
/// <summary>
/// <see cref="BulkConvertByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertByteToNormalizedFloatReduce(
ref ReadOnlySpan<byte> source,
ref Span<float> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = ImageMaths.ModuloP2(source.Length, Vector<byte>.Count);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertByteToNormalizedFloat(source.Slice(0, adjustedCount), dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// <see cref="BulkConvertNormalizedFloatToByteClampOverflows"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce(
ref ReadOnlySpan<float> source,
ref Span<byte> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
if (!IsAvailable)
{
return;
}
int remainder = ImageMaths.ModuloP2(source.Length, Vector<byte>.Count);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertNormalizedFloatToByteClampOverflows(
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// Implementation <see cref="SimdUtils.BulkConvertByteToNormalizedFloat"/>, which is faster on new RyuJIT runtime.
/// </summary>
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
VerifySpanInput(source, dest, Vector<byte>.Count);
int n = dest.Length / Vector<byte>.Count;
ref Vector<byte> sourceBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(source));
ref Vector<float> destBase = ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(dest));
for (int i = 0; i < n; i++)
{
Vector<byte> b = Unsafe.Add(ref sourceBase, i);
Vector.Widen(b, out Vector<ushort> s0, out Vector<ushort> s1);
Vector.Widen(s0, out Vector<uint> w0, out Vector<uint> w1);
Vector.Widen(s1, out Vector<uint> w2, out Vector<uint> w3);
Vector<float> f0 = ConvertToSingle(w0);
Vector<float> f1 = ConvertToSingle(w1);
Vector<float> f2 = ConvertToSingle(w2);
Vector<float> f3 = ConvertToSingle(w3);
ref Vector<float> d = ref Unsafe.Add(ref destBase, i * 4);
d = f0;
Unsafe.Add(ref d, 1) = f1;
Unsafe.Add(ref d, 2) = f2;
Unsafe.Add(ref d, 3) = f3;
}
}
/// <summary>
/// Implementation of <see cref="SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows"/>, which is faster on new .NET runtime.
/// </summary>
internal static void BulkConvertNormalizedFloatToByteClampOverflows(
ReadOnlySpan<float> source,
Span<byte> dest)
{
VerifySpanInput(source, dest, Vector<byte>.Count);
int n = dest.Length / Vector<byte>.Count;
ref Vector<float> sourceBase =
ref Unsafe.As<float, Vector<float>>(ref MemoryMarshal.GetReference(source));
ref Vector<byte> destBase = ref Unsafe.As<byte, Vector<byte>>(ref MemoryMarshal.GetReference(dest));
for (int i = 0; i < n; i++)
{
ref Vector<float> s = ref Unsafe.Add(ref sourceBase, i * 4);
Vector<float> f0 = s;
Vector<float> f1 = Unsafe.Add(ref s, 1);
Vector<float> f2 = Unsafe.Add(ref s, 2);
Vector<float> f3 = Unsafe.Add(ref s, 3);
Vector<uint> w0 = ConvertToUInt32(f0);
Vector<uint> w1 = ConvertToUInt32(f1);
Vector<uint> w2 = ConvertToUInt32(f2);
Vector<uint> w3 = ConvertToUInt32(f3);
Vector<ushort> u0 = Vector.Narrow(w0, w1);
Vector<ushort> u1 = Vector.Narrow(w2, w3);
Vector<byte> b = Vector.Narrow(u0, u1);
Unsafe.Add(ref destBase, i) = b;
}
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<uint> ConvertToUInt32(Vector<float> vf)
{
Vector<float> maxBytes = new Vector<float>(255f);
vf *= maxBytes;
vf += new Vector<float>(0.5f);
vf = Vector.Min(Vector.Max(vf, Vector<float>.Zero), maxBytes);
Vector<int> vi = Vector.ConvertToInt32(vf);
return Vector.AsVectorUInt32(vi);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Vector<float> ConvertToSingle(Vector<uint> u)
{
Vector<int> vi = Vector.AsVectorInt32(u);
Vector<float> v = Vector.ConvertToSingle(vi);
v *= new Vector<float>(1f / 255f);
return v;
}
}
}
}

151
src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs

@ -0,0 +1,151 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// ReSharper disable MemberHidesStaticFromOuterClass
namespace SixLabors.ImageSharp
{
internal static partial class SimdUtils
{
/// <summary>
/// Fallback implementation based on <see cref="Vector4"/> (128bit).
/// For <see cref="Vector4"/>, efficient software fallback implementations are present,
/// and we hope that even mono's JIT is able to emit SIMD instructions for that type :P
/// </summary>
public static class FallbackIntrinsics128
{
/// <summary>
/// <see cref="BulkConvertByteToNormalizedFloat"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertByteToNormalizedFloatReduce(
ref ReadOnlySpan<byte> source,
ref Span<float> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
int remainder = ImageMaths.Modulo4(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertByteToNormalizedFloat(
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// <see cref="BulkConvertNormalizedFloatToByteClampOverflows"/> as many elements as possible, slicing them down (keeping the remainder).
/// </summary>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertNormalizedFloatToByteClampOverflowsReduce(
ref ReadOnlySpan<float> source,
ref Span<byte> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
int remainder = ImageMaths.Modulo4(source.Length);
int adjustedCount = source.Length - remainder;
if (adjustedCount > 0)
{
BulkConvertNormalizedFloatToByteClampOverflows(
source.Slice(0, adjustedCount),
dest.Slice(0, adjustedCount));
source = source.Slice(adjustedCount);
dest = dest.Slice(adjustedCount);
}
}
/// <summary>
/// Implementation of <see cref="SimdUtils.BulkConvertByteToNormalizedFloat"/> using <see cref="Vector4"/>.
/// </summary>
[MethodImpl(InliningOptions.ColdPath)]
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
VerifySpanInput(source, dest, 4);
int count = dest.Length / 4;
if (count == 0)
{
return;
}
ref ByteVector4 sBase = ref Unsafe.As<byte, ByteVector4>(ref MemoryMarshal.GetReference(source));
ref Vector4 dBase = ref Unsafe.As<float, Vector4>(ref MemoryMarshal.GetReference(dest));
const float Scale = 1f / 255f;
Vector4 d = default;
for (int i = 0; i < count; i++)
{
ref ByteVector4 s = ref Unsafe.Add(ref sBase, i);
d.X = s.X;
d.Y = s.Y;
d.Z = s.Z;
d.W = s.W;
d *= Scale;
Unsafe.Add(ref dBase, i) = d;
}
}
/// <summary>
/// Implementation of <see cref="SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows"/> using <see cref="Vector4"/>.
/// </summary>
[MethodImpl(InliningOptions.ColdPath)]
internal static void BulkConvertNormalizedFloatToByteClampOverflows(
ReadOnlySpan<float> source,
Span<byte> dest)
{
VerifySpanInput(source, dest, 4);
int count = source.Length / 4;
if (count == 0)
{
return;
}
ref Vector4 sBase = ref Unsafe.As<float, Vector4>(ref MemoryMarshal.GetReference(source));
ref ByteVector4 dBase = ref Unsafe.As<byte, ByteVector4>(ref MemoryMarshal.GetReference(dest));
var half = new Vector4(0.5f);
var maxBytes = new Vector4(255f);
for (int i = 0; i < count; i++)
{
Vector4 s = Unsafe.Add(ref sBase, i);
s *= maxBytes;
s += half;
// I'm not sure if Vector4.Clamp() is properly implemented with intrinsics.
s = Vector4.Max(Vector4.Zero, s);
s = Vector4.Min(maxBytes, s);
ref ByteVector4 d = ref Unsafe.Add(ref dBase, i);
d.X = (byte)s.X;
d.Y = (byte)s.Y;
d.Z = (byte)s.Z;
d.W = (byte)s.W;
}
}
[StructLayout(LayoutKind.Sequential)]
private struct ByteVector4
{
public byte X;
public byte Y;
public byte Z;
public byte W;
}
}
}
}

185
src/ImageSharp/Common/Helpers/SimdUtils.cs

@ -0,0 +1,185 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Diagnostics;
using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp
{
/// <summary>
/// Various extension and utility methods for <see cref="Vector4"/> and <see cref="Vector{T}"/> utilizing SIMD capabilities
/// </summary>
internal static partial class SimdUtils
{
/// <summary>
/// Gets a value indicating whether the code is being executed on AVX2 CPU where both float and integer registers are of size 256 byte.
/// </summary>
public static bool IsAvx2CompatibleArchitecture { get; } =
Vector.IsHardwareAccelerated && Vector<float>.Count == 8 && Vector<int>.Count == 8;
/// <summary>
/// Transform all scalars in 'v' in a way that converting them to <see cref="int"/> would have rounding semantics.
/// </summary>
/// <param name="v">The vector</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector4 PseudoRound(this Vector4 v)
{
var sign = Vector4.Clamp(v, new Vector4(-1), new Vector4(1));
return v + (sign * 0.5f);
}
/// <summary>
/// Rounds all values in 'v' to the nearest integer following <see cref="MidpointRounding.ToEven"/> semantics.
/// Source:
/// <see>
/// <cref>https://github.com/g-truc/glm/blob/master/glm/simd/common.h#L110</cref>
/// </see>
/// </summary>
/// <param name="v">The vector</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal static Vector<float> FastRound(this Vector<float> v)
{
Vector<int> magic0 = new Vector<int>(int.MinValue); // 0x80000000
Vector<float> sgn0 = Vector.AsVectorSingle(magic0);
Vector<float> and0 = Vector.BitwiseAnd(sgn0, v);
Vector<float> or0 = Vector.BitwiseOr(and0, new Vector<float>(8388608.0f));
Vector<float> add0 = Vector.Add(v, or0);
Vector<float> sub0 = Vector.Subtract(add0, or0);
return sub0;
}
/// <summary>
/// Converts all input <see cref="byte"/>-s to <see cref="float"/>-s normalized into [0..1].
/// <paramref name="source"/> should be the of the same size as <paramref name="dest"/>,
/// but there are no restrictions on the span's length.
/// </summary>
/// <param name="source">The source span of bytes</param>
/// <param name="dest">The destination span of floats</param>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertByteToNormalizedFloat(ReadOnlySpan<byte> source, Span<float> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
#if NETCOREAPP2_1
ExtendedIntrinsics.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest);
#else
BasicIntrinsics256.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest);
#endif
FallbackIntrinsics128.BulkConvertByteToNormalizedFloatReduce(ref source, ref dest);
// Deal with the remainder:
if (source.Length > 0)
{
ConverByteToNormalizedFloatRemainder(source, dest);
}
}
/// <summary>
/// Convert all <see cref="float"/> values normalized into [0..1] from 'source' into 'dest' buffer of <see cref="byte"/>.
/// The values are scaled up into [0-255] and rounded, overflows are clamped.
/// <paramref name="source"/> should be the of the same size as <paramref name="dest"/>,
/// but there are no restrictions on the span's length.
/// </summary>
/// <param name="source">The source span of floats</param>
/// <param name="dest">The destination span of bytes</param>
[MethodImpl(InliningOptions.ShortMethod)]
internal static void BulkConvertNormalizedFloatToByteClampOverflows(ReadOnlySpan<float> source, Span<byte> dest)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
#if NETCOREAPP2_1
ExtendedIntrinsics.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest);
#else
BasicIntrinsics256.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest);
#endif
FallbackIntrinsics128.BulkConvertNormalizedFloatToByteClampOverflowsReduce(ref source, ref dest);
// Deal with the remainder:
if (source.Length > 0)
{
ConvertNormalizedFloatToByteRemainder(source, dest);
}
}
[MethodImpl(InliningOptions.ColdPath)]
private static void ConverByteToNormalizedFloatRemainder(ReadOnlySpan<byte> source, Span<float> dest)
{
ref byte sBase = ref MemoryMarshal.GetReference(source);
ref float dBase = ref MemoryMarshal.GetReference(dest);
// There are at most 3 elements at this point, having a for loop is overkill.
// Let's minimize the no. of instructions!
switch (source.Length)
{
case 3:
Unsafe.Add(ref dBase, 2) = Unsafe.Add(ref sBase, 2) / 255f;
goto case 2;
case 2:
Unsafe.Add(ref dBase, 1) = Unsafe.Add(ref sBase, 1) / 255f;
goto case 1;
case 1:
dBase = sBase / 255f;
break;
}
}
[MethodImpl(InliningOptions.ColdPath)]
private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan<float> source, Span<byte> dest)
{
ref float sBase = ref MemoryMarshal.GetReference(source);
ref byte dBase = ref MemoryMarshal.GetReference(dest);
switch (source.Length)
{
case 3:
Unsafe.Add(ref dBase, 2) = ConvertToByte(Unsafe.Add(ref sBase, 2));
goto case 2;
case 2:
Unsafe.Add(ref dBase, 1) = ConvertToByte(Unsafe.Add(ref sBase, 1));
goto case 1;
case 1:
dBase = ConvertToByte(sBase);
break;
}
}
[MethodImpl(InliningOptions.ShortMethod)]
private static byte ConvertToByte(float f) => (byte)ComparableExtensions.Clamp((f * 255f) + 0.5f, 0, 255f);
[Conditional("DEBUG")]
private static void VerifyIsAvx2Compatible(string operation)
{
if (!IsAvx2CompatibleArchitecture)
{
throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!");
}
}
[Conditional("DEBUG")]
private static void VerifySpanInput(ReadOnlySpan<byte> source, Span<float> dest, int shouldBeDivisibleBy)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
DebugGuard.IsTrue(
ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0,
nameof(source),
$"length should be divisable by {shouldBeDivisibleBy}!");
}
[Conditional("DEBUG")]
private static void VerifySpanInput(ReadOnlySpan<float> source, Span<byte> dest, int shouldBeDivisibleBy)
{
DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!");
DebugGuard.IsTrue(
ImageMaths.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0,
nameof(source),
$"length should be divisable by {shouldBeDivisibleBy}!");
}
}
}

4
src/ImageSharp/Common/Helpers/TestHelpers.cs

@ -13,9 +13,7 @@ namespace SixLabors.ImageSharp.Common.Helpers
/// Only intended to be used in tests! /// Only intended to be used in tests!
/// </summary> /// </summary>
internal const string ImageSharpBuiltAgainst = internal const string ImageSharpBuiltAgainst =
#if NETSTANDARD1_1 #if NETCOREAPP2_1
"netstandard1.1";
#elif NETCOREAPP2_1
"netcoreapp2.1"; "netcoreapp2.1";
#else #else
"netstandard2.0"; "netstandard2.0";

109
src/ImageSharp/Common/Tuples/Octet.cs

@ -0,0 +1,109 @@
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Tuples
{
/// <summary>
/// Contains 8 element value tuples of various types.
/// </summary>
internal static class Octet
{
/// <summary>
/// Value tuple of <see cref="uint"/>-s
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 8 * sizeof(uint))]
public struct OfUInt32
{
[FieldOffset(0 * sizeof(uint))]
public uint V0;
[FieldOffset(1 * sizeof(uint))]
public uint V1;
[FieldOffset(2 * sizeof(uint))]
public uint V2;
[FieldOffset(3 * sizeof(uint))]
public uint V3;
[FieldOffset(4 * sizeof(uint))]
public uint V4;
[FieldOffset(5 * sizeof(uint))]
public uint V5;
[FieldOffset(6 * sizeof(uint))]
public uint V6;
[FieldOffset(7 * sizeof(uint))]
public uint V7;
public override string ToString()
{
return $"{nameof(Octet)}.{nameof(OfUInt32)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})";
}
[MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(ref OfByte src)
{
this.V0 = src.V0;
this.V1 = src.V1;
this.V2 = src.V2;
this.V3 = src.V3;
this.V4 = src.V4;
this.V5 = src.V5;
this.V6 = src.V6;
this.V7 = src.V7;
}
}
/// <summary>
/// Value tuple of <see cref="byte"/>-s
/// </summary>
[StructLayout(LayoutKind.Explicit, Size = 8)]
public struct OfByte
{
[FieldOffset(0)]
public byte V0;
[FieldOffset(1)]
public byte V1;
[FieldOffset(2)]
public byte V2;
[FieldOffset(3)]
public byte V3;
[FieldOffset(4)]
public byte V4;
[FieldOffset(5)]
public byte V5;
[FieldOffset(6)]
public byte V6;
[FieldOffset(7)]
public byte V7;
public override string ToString()
{
return $"{nameof(Octet)}.{nameof(OfByte)}({this.V0},{this.V1},{this.V2},{this.V3},{this.V4},{this.V5},{this.V6},{this.V7})";
}
[MethodImpl(InliningOptions.ShortMethod)]
public void LoadFrom(ref OfUInt32 src)
{
this.V0 = (byte)src.V0;
this.V1 = (byte)src.V1;
this.V2 = (byte)src.V2;
this.V3 = (byte)src.V3;
this.V4 = (byte)src.V4;
this.V5 = (byte)src.V5;
this.V6 = (byte)src.V6;
this.V7 = (byte)src.V7;
}
}
}
}

12
src/ImageSharp/Common/Tuples/Vector4Pair.cs

@ -2,11 +2,12 @@
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
namespace SixLabors.ImageSharp.Common.Tuples namespace SixLabors.ImageSharp.Tuples
{ {
/// <summary> /// <summary>
/// Its faster to process multiple Vector4-s together, so let's pair them! /// Its faster to process multiple Vector4-s together, so let's pair them!
/// On AVX2 this pair should be convertible to <see cref="Vector{T}"/> of <see cref="float"/>! /// On AVX2 this pair should be convertible to <see cref="Vector{T}"/> of <see cref="float"/>!
/// TODO: Investigate defining this as union with an Octet.OfSingle type.
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
internal struct Vector4Pair internal struct Vector4Pair
@ -15,8 +16,6 @@ namespace SixLabors.ImageSharp.Common.Tuples
public Vector4 B; public Vector4 B;
private static readonly Vector4 Scale = new Vector4(1 / 255f);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public void MultiplyInplace(float value) public void MultiplyInplace(float value)
{ {
@ -52,8 +51,9 @@ namespace SixLabors.ImageSharp.Common.Tuples
b = b.FastRound(); b = b.FastRound();
// Downscale by 1/255 // Downscale by 1/255
this.A *= Scale; var scale = new Vector4(1 / 255f);
this.B *= Scale; this.A *= scale;
this.B *= scale;
} }
/// <summary> /// <summary>
@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Common.Tuples
public override string ToString() public override string ToString()
{ {
return $"{this.A}, {this.B}"; return $"{nameof(Vector4Pair)}({this.A}, {this.B})";
} }
} }
} }

8
src/ImageSharp/Configuration.cs

@ -3,15 +3,12 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Threading.Tasks;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Bmp;
using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Gif;
using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Jpeg;
using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Png;
#if !NETSTANDARD1_1
using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.IO;
#endif
using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing;
using SixLabors.Memory; using SixLabors.Memory;
@ -100,12 +97,10 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
internal int MaxHeaderSize => this.ImageFormatsManager.MaxHeaderSize; internal int MaxHeaderSize => this.ImageFormatsManager.MaxHeaderSize;
#if !NETSTANDARD1_1
/// <summary> /// <summary>
/// Gets or sets the filesystem helper for accessing the local file system. /// Gets or sets the filesystem helper for accessing the local file system.
/// </summary> /// </summary>
internal IFileSystem FileSystem { get; set; } = new LocalFileSystem(); internal IFileSystem FileSystem { get; set; } = new LocalFileSystem();
#endif
/// <summary> /// <summary>
/// Gets or sets the image operations provider factory. /// Gets or sets the image operations provider factory.
@ -135,10 +130,7 @@ namespace SixLabors.ImageSharp
MemoryAllocator = this.MemoryAllocator, MemoryAllocator = this.MemoryAllocator,
ImageOperationsProvider = this.ImageOperationsProvider, ImageOperationsProvider = this.ImageOperationsProvider,
ReadOrigin = this.ReadOrigin, ReadOrigin = this.ReadOrigin,
#if !NETSTANDARD1_1
FileSystem = this.FileSystem FileSystem = this.FileSystem
#endif
}; };
} }

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

@ -219,8 +219,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
TPixel color = default; TPixel color = default;
var rgba = new Rgba32(0, 0, 0, 255);
using (Buffer2D<byte> buffer = this.memoryAllocator.Allocate2D<byte>(width, height, AllocationOptions.Clean)) using (Buffer2D<byte> buffer = this.memoryAllocator.Allocate2D<byte>(width, height, AllocationOptions.Clean))
{ {
this.UncompressRle8(width, buffer.GetSpan()); this.UncompressRle8(width, buffer.GetSpan());
@ -233,8 +231,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int x = 0; x < width; x++) for (int x = 0; x < width; x++)
{ {
rgba.Bgr = Unsafe.As<byte, Bgr24>(ref colors[bufferRow[x] * 4]); color.PackFromBgr24(Unsafe.As<byte, Bgr24>(ref colors[bufferRow[x] * 4]));
color.PackFromRgba32(rgba);
pixelRow[x] = color; pixelRow[x] = color;
} }
} }
@ -352,8 +349,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean)) using (IManagedByteBuffer row = this.memoryAllocator.AllocateManagedByteBuffer(arrayWidth + padding, AllocationOptions.Clean))
{ {
TPixel color = default; TPixel color = default;
var rgba = new Rgba32(0, 0, 0, 255);
Span<byte> rowSpan = row.GetSpan(); Span<byte> rowSpan = row.GetSpan();
for (int y = 0; y < height; y++) for (int y = 0; y < height; y++)
@ -363,7 +358,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int offset = 0; int offset = 0;
Span<TPixel> pixelRow = pixels.GetRowSpan(newY); Span<TPixel> pixelRow = pixels.GetRowSpan(newY);
// TODO: Could use PixelOperations here!
for (int x = 0; x < arrayWidth; x++) for (int x = 0; x < arrayWidth; x++)
{ {
int colOffset = x * ppb; int colOffset = x * ppb;
@ -371,9 +365,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{ {
int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4;
// Stored in b-> g-> r order. color.PackFromBgr24(Unsafe.As<byte, Bgr24>(ref colors[colorIndex]));
rgba.Bgr = Unsafe.As<byte, Bgr24>(ref colors[colorIndex]);
color.PackFromRgba32(rgba);
pixelRow[newX] = color; pixelRow[newX] = color;
} }
@ -397,7 +389,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
int padding = CalculatePadding(width, 2); int padding = CalculatePadding(width, 2);
int stride = (width * 2) + padding; int stride = (width * 2) + padding;
TPixel color = default; TPixel color = default;
var rgba = new Rgba32(0, 0, 0, 255);
using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride)) using (IManagedByteBuffer buffer = this.memoryAllocator.AllocateManagedByteBuffer(stride))
{ {
@ -412,11 +403,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{ {
short temp = BitConverter.ToInt16(buffer.Array, offset); short temp = BitConverter.ToInt16(buffer.Array, offset);
rgba.R = GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10); var rgb = new Rgb24(
rgba.G = GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5); GetBytesFrom5BitValue((temp & Rgb16RMask) >> 10),
rgba.B = GetBytesFrom5BitValue(temp & Rgb16BMask); GetBytesFrom5BitValue((temp & Rgb16GMask) >> 5),
GetBytesFrom5BitValue(temp & Rgb16BMask));
color.PackFromRgba32(rgba); color.PackFromRgb24(rgb);
pixelRow[x] = color; pixelRow[x] = color;
offset += 2; offset += 2;
} }
@ -537,7 +529,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp
this.metaData = meta; this.metaData = meta;
short bitsPerPixel = this.infoHeader.BitsPerPixel; short bitsPerPixel = this.infoHeader.BitsPerPixel;
var bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); BmpMetaData bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance);
// We can only encode at these bit rates so far. // We can only encode at these bit rates so far.
if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24) if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24)

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

@ -101,9 +101,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
var fileHeader = new BmpFileHeader( var fileHeader = new BmpFileHeader(
type: 19778, // BM type: 19778, // BM
offset: 54, fileSize: 54 + infoHeader.ImageSize,
reserved: 0, reserved: 0,
fileSize: 54 + infoHeader.ImageSize); offset: 54);
#if NETCOREAPP2_1 #if NETCOREAPP2_1
Span<byte> buffer = stackalloc byte[40]; Span<byte> buffer = stackalloc byte[40];

6
src/ImageSharp/Formats/Gif/GifConstants.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// The ASCII encoded bytes used to identify the GIF file. /// The ASCII encoded bytes used to identify the GIF file.
/// </summary> /// </summary>
internal static readonly byte[] MagicNumber = Encoding.UTF8.GetBytes(FileType + FileVersion); internal static readonly byte[] MagicNumber = Encoding.ASCII.GetBytes(FileType + FileVersion);
/// <summary> /// <summary>
/// The extension block introducer <value>!</value>. /// The extension block introducer <value>!</value>.
@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// The ASCII encoded application identification bytes. /// The ASCII encoded application identification bytes.
/// </summary> /// </summary>
internal static readonly byte[] NetscapeApplicationIdentificationBytes = Encoding.UTF8.GetBytes(NetscapeApplicationIdentification); internal static readonly byte[] NetscapeApplicationIdentificationBytes = Encoding.ASCII.GetBytes(NetscapeApplicationIdentification);
/// <summary> /// <summary>
/// The Netscape looping application sub block size. /// The Netscape looping application sub block size.
@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <summary> /// <summary>
/// Gets the default encoding to use when reading comments. /// Gets the default encoding to use when reading comments.
/// </summary> /// </summary>
public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); public static readonly Encoding DefaultEncoding = Encoding.ASCII;
/// <summary> /// <summary>
/// The list of mimetypes that equate to a gif. /// The list of mimetypes that equate to a gif.

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

@ -481,22 +481,36 @@ namespace SixLabors.ImageSharp.Formats.Gif
} }
ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY)); ref TPixel rowRef = ref MemoryMarshal.GetReference(imageFrame.GetPixelRowSpan(writeY));
var rgba = new Rgba32(0, 0, 0, 255); bool transFlag = this.graphicsControlExtension.TransparencyFlag;
// #403 The left + width value can be larger than the image width if (!transFlag)
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++)
{ {
int index = Unsafe.Add(ref indicesRef, i); // #403 The left + width value can be larger than the image width
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++)
if (!this.graphicsControlExtension.TransparencyFlag
|| this.graphicsControlExtension.TransparencyIndex != index)
{ {
int index = Unsafe.Add(ref indicesRef, i);
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x); ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
rgba.Rgb = colorTable[index]; Rgb24 rgb = colorTable[index];
pixel.PackFromRgba32(rgba); pixel.PackFromRgb24(rgb);
i++;
} }
}
else
{
byte transIndex = this.graphicsControlExtension.TransparencyIndex;
for (int x = descriptor.Left; x < descriptor.Left + descriptor.Width && x < imageWidth; x++)
{
int index = Unsafe.Add(ref indicesRef, i);
if (transIndex != index)
{
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
Rgb24 rgb = colorTable[index];
pixel.PackFromRgb24(rgb);
}
i++; i++;
}
} }
} }

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
using System.IO; using System.IO;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -210,16 +211,20 @@ namespace SixLabors.ImageSharp.Formats.Gif
{ {
// Transparent pixels are much more likely to be found at the end of a palette // Transparent pixels are much more likely to be found at the end of a palette
int index = -1; int index = -1;
Rgba32 trans = default; int length = quantized.Palette.Length;
ref TPixel paletteRef = ref MemoryMarshal.GetReference(quantized.Palette.AsSpan()); using (IMemoryOwner<Rgba32> rgbaBuffer = this.memoryAllocator.Allocate<Rgba32>(length))
for (int i = quantized.Palette.Length - 1; i >= 0; i--)
{ {
ref TPixel entry = ref Unsafe.Add(ref paletteRef, i); Span<Rgba32> rgbaSpan = rgbaBuffer.GetSpan();
entry.ToRgba32(ref trans); ref Rgba32 paletteRef = ref MemoryMarshal.GetReference(rgbaSpan);
if (trans.Equals(default)) PixelOperations<TPixel>.Instance.ToRgba32(quantized.Palette, rgbaSpan, length);
for (int i = quantized.Palette.Length - 1; i >= 0; i--)
{ {
index = i; if (Unsafe.Add(ref paletteRef, i).Equals(default))
{
index = i;
}
} }
} }
@ -406,24 +411,13 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void WriteColorTable<TPixel>(QuantizedFrame<TPixel> image, Stream stream) private void WriteColorTable<TPixel>(QuantizedFrame<TPixel> image, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
int pixelCount = image.Palette.Length;
// The maximium number of colors for the bit depth // The maximium number of colors for the bit depth
int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3;
Rgb24 rgb = default; int pixelCount = image.Palette.Length;
using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
{ {
ref TPixel paletteRef = ref MemoryMarshal.GetReference(image.Palette.AsSpan()); PixelOperations<TPixel>.Instance.ToRgb24Bytes(image.Palette.AsSpan(), colorTable.GetSpan(), pixelCount);
ref Rgb24 rgb24Ref = ref Unsafe.As<byte, Rgb24>(ref MemoryMarshal.GetReference(colorTable.GetSpan()));
for (int i = 0; i < pixelCount; i++)
{
ref TPixel entry = ref Unsafe.Add(ref paletteRef, i);
entry.ToRgb24(ref rgb);
Unsafe.Add(ref rgb24Ref, i) = rgb;
}
// Write the palette to the stream
stream.Write(colorTable.Array, 0, colorTableLength); stream.Write(colorTable.Array, 0, colorTableLength);
} }
} }

4
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs

@ -6,7 +6,7 @@ using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Tuples;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
{ {
@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order:
ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i);
destination.Collect(ref r, ref g, ref b); destination.Pack(ref r, ref g, ref b);
} }
} }
} }

4
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs

@ -6,7 +6,7 @@ using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.ImageSharp.Common.Tuples; using SixLabors.ImageSharp.Tuples;
// ReSharper disable ImpureMethodCallOnReadonlyValueField // ReSharper disable ImpureMethodCallOnReadonlyValueField
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order: // Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order:
ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i); ref Vector4Octet destination = ref Unsafe.Add(ref resultBase, i);
destination.Collect(ref rr, ref gg, ref bb); destination.Pack(ref rr, ref gg, ref bb);
} }
} }
} }

6
src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs

@ -6,8 +6,8 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Numerics; using System.Numerics;
using SixLabors.ImageSharp.Common.Tuples;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.Tuples;
using SixLabors.Memory; using SixLabors.Memory;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
@ -157,9 +157,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
public Vector4 V0, V1, V2, V3, V4, V5, V6, V7; public Vector4 V0, V1, V2, V3, V4, V5, V6, V7;
/// <summary> /// <summary>
/// Collect (r0,r1...r8) (g0,g1...g8) (b0,b1...b8) vector values in the expected (r0,g0,g1,1), (r1,g1,g2,1) ... order. /// Pack (r0,r1...r7) (g0,g1...g7) (b0,b1...b7) vector values as (r0,g0,b0,1), (r1,g1,b1,1) ...
/// </summary> /// </summary>
public void Collect(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b) public void Pack(ref Vector4Pair r, ref Vector4Pair g, ref Vector4Pair b)
{ {
this.V0.X = r.A.X; this.V0.X = r.A.X;
this.V0.Y = g.A.X; this.V0.Y = g.A.X;

8
src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs

@ -14,22 +14,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// <summary> /// <summary>
/// Describes the EXIF specific markers /// Describes the EXIF specific markers
/// </summary> /// </summary>
public static readonly byte[] JFifMarker = Encoding.UTF8.GetBytes("JFIF\0"); public static readonly byte[] JFifMarker = Encoding.ASCII.GetBytes("JFIF\0");
/// <summary> /// <summary>
/// Describes the EXIF specific markers /// Describes the EXIF specific markers
/// </summary> /// </summary>
public static readonly byte[] IccMarker = Encoding.UTF8.GetBytes("ICC_PROFILE\0"); public static readonly byte[] IccMarker = Encoding.ASCII.GetBytes("ICC_PROFILE\0");
/// <summary> /// <summary>
/// Describes the ICC specific markers /// Describes the ICC specific markers
/// </summary> /// </summary>
public static readonly byte[] ExifMarker = Encoding.UTF8.GetBytes("Exif\0\0"); public static readonly byte[] ExifMarker = Encoding.ASCII.GetBytes("Exif\0\0");
/// <summary> /// <summary>
/// Describes Adobe specific markers <see href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe"/> /// Describes Adobe specific markers <see href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe"/>
/// </summary> /// </summary>
public static readonly byte[] AdobeMarker = Encoding.UTF8.GetBytes("Adobe"); public static readonly byte[] AdobeMarker = Encoding.ASCII.GetBytes("Adobe");
/// <summary> /// <summary>
/// Returns a value indicating whether the passed bytes are a match to the profile identifier /// Returns a value indicating whether the passed bytes are a match to the profile identifier

2
src/ImageSharp/Formats/Png/PngConstants.cs

@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <summary> /// <summary>
/// The default encoding for text metadata. /// The default encoding for text metadata.
/// </summary> /// </summary>
public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); public static readonly Encoding DefaultEncoding = Encoding.ASCII;
/// <summary> /// <summary>
/// The list of mimetypes that equate to a png. /// The list of mimetypes that equate to a png.

2
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -1005,7 +1005,7 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.crc.Value != chunk.Crc) if (this.crc.Value != chunk.Crc)
{ {
string chunkTypeName = Encoding.UTF8.GetString(chunkType); string chunkTypeName = Encoding.ASCII.GetString(chunkType);
throw new ImageFormatException($"CRC Error. PNG {chunkTypeName} chunk is corrupt!"); throw new ImageFormatException($"CRC Error. PNG {chunkTypeName} chunk is corrupt!");
} }

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

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
using System.Buffers.Binary; using System.Buffers.Binary;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
@ -312,11 +313,6 @@ namespace SixLabors.ImageSharp.Formats.Png
private void CollectGrayscaleBytes<TPixel>(ReadOnlySpan<TPixel> rowSpan) private void CollectGrayscaleBytes<TPixel>(ReadOnlySpan<TPixel> rowSpan)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
// Use ITU-R recommendation 709 to match libpng.
const float RX = .2126F;
const float GX = .7152F;
const float BX = .0722F;
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
Span<byte> rawScanlineSpan = this.rawScanline.GetSpan(); Span<byte> rawScanlineSpan = this.rawScanline.GetSpan();
ref byte rawScanlineSpanRef = ref MemoryMarshal.GetReference(rawScanlineSpan); ref byte rawScanlineSpanRef = ref MemoryMarshal.GetReference(rawScanlineSpan);
@ -327,12 +323,18 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.use16Bit) if (this.use16Bit)
{ {
// 16 bit grayscale // 16 bit grayscale
Rgb48 rgb = default; using (IMemoryOwner<Gray16> luminanceBuffer = this.memoryAllocator.Allocate<Gray16>(rowSpan.Length))
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2)
{ {
Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); Span<Gray16> luminanceSpan = luminanceBuffer.GetSpan();
ushort luminance = (ushort)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); ref Gray16 luminanceRef = ref MemoryMarshal.GetReference(luminanceSpan);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); PixelOperations<TPixel>.Instance.ToGray16(rowSpan, luminanceSpan, rowSpan.Length);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < luminanceSpan.Length; x++, o += 2)
{
Gray16 luminance = Unsafe.Add(ref luminanceRef, x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance.PackedValue);
}
} }
} }
else else
@ -340,12 +342,7 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.bitDepth == 8) if (this.bitDepth == 8)
{ {
// 8 bit grayscale // 8 bit grayscale
Rgb24 rgb = default; PixelOperations<TPixel>.Instance.ToGray8Bytes(rowSpan, rawScanlineSpan, rowSpan.Length);
for (int x = 0; x < rowSpan.Length; x++)
{
Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb);
Unsafe.Add(ref rawScanlineSpanRef, x) = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B));
}
} }
else else
{ {
@ -356,14 +353,9 @@ namespace SixLabors.ImageSharp.Formats.Png
Span<byte> tempSpan = temp.GetSpan(); Span<byte> tempSpan = temp.GetSpan();
ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan); ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan);
Rgb24 rgb = default; // We need to first create an array of luminance bytes then scale them down to the correct bit depth.
for (int x = 0; x < rowSpan.Length; x++) PixelOperations<TPixel>.Instance.ToGray8Bytes(rowSpan, tempSpan, rowSpan.Length);
{ this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth, scaleFactor);
Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb);
float luminance = ((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)) / scaleFactor;
Unsafe.Add(ref tempSpanRef, x) = (byte)luminance;
this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth);
}
} }
} }
} }
@ -373,23 +365,31 @@ namespace SixLabors.ImageSharp.Formats.Png
if (this.use16Bit) if (this.use16Bit)
{ {
// 16 bit grayscale + alpha // 16 bit grayscale + alpha
Rgba64 rgba = default; // TODO: Should we consider in the future a GrayAlpha32 type.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 4) using (IMemoryOwner<Rgba64> rgbaBuffer = this.memoryAllocator.Allocate<Rgba64>(rowSpan.Length))
{ {
Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); Span<Rgba64> rgbaSpan = rgbaBuffer.GetSpan();
ushort luminance = (ushort)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); PixelOperations<TPixel>.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rgbaSpan.Length; x++, o += 4)
{
Rgba64 rgba = Unsafe.Add(ref rgbaRef, x);
ushort luminance = ImageMaths.Get16BitBT709Luminance(rgba.R, rgba.G, rgba.B);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A);
}
} }
} }
else else
{ {
// 8 bit grayscale + alpha // 8 bit grayscale + alpha
Rgba32 rgba = default; // TODO: Should we consider in the future a GrayAlpha16 type.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2)
{ {
Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); var rgba = Unsafe.Add(ref rowSpanRef, x).ToRgba32();
Unsafe.Add(ref rawScanlineSpanRef, o) = (byte)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); Unsafe.Add(ref rawScanlineSpanRef, o) = ImageMaths.Get8BitBT709Luminance(rgba.R, rgba.G, rgba.B);
Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A;
} }
} }
@ -425,15 +425,21 @@ namespace SixLabors.ImageSharp.Formats.Png
case 8: case 8:
{ {
// 16 bit Rgba // 16 bit Rgba
Rgba64 rgba = default; using (IMemoryOwner<Rgba64> rgbaBuffer = this.memoryAllocator.Allocate<Rgba64>(rowSpan.Length))
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8)
{ {
Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); Span<Rgba64> rgbaSpan = rgbaBuffer.GetSpan();
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); ref Rgba64 rgbaRef = ref MemoryMarshal.GetReference(rgbaSpan);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); PixelOperations<TPixel>.Instance.ToRgba64(rowSpan, rgbaSpan, rowSpan.Length);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A); // Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8)
{
Rgba64 rgba = Unsafe.Add(ref rgbaRef, x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 6, 2), rgba.A);
}
} }
break; break;
@ -442,14 +448,20 @@ namespace SixLabors.ImageSharp.Formats.Png
default: default:
{ {
// 16 bit Rgb // 16 bit Rgb
Rgb48 rgb = default; using (IMemoryOwner<Rgb48> rgbBuffer = this.memoryAllocator.Allocate<Rgb48>(rowSpan.Length))
ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan);
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6)
{ {
Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); Span<Rgb48> rgbSpan = rgbBuffer.GetSpan();
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); ref Rgb48 rgbRef = ref MemoryMarshal.GetReference(rgbSpan);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); PixelOperations<TPixel>.Instance.ToRgb48(rowSpan, rgbSpan, rowSpan.Length);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B);
// Can't map directly to byte array as it's big endian.
for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6)
{
Rgb48 rgb = Unsafe.Add(ref rgbRef, x);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G);
BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B);
}
} }
break; break;
@ -624,7 +636,6 @@ namespace SixLabors.ImageSharp.Formats.Png
TPixel[] palette = quantized.Palette; TPixel[] palette = quantized.Palette;
int paletteLength = Math.Min(palette.Length, 256); int paletteLength = Math.Min(palette.Length, 256);
int colorTableLength = paletteLength * 3; int colorTableLength = paletteLength * 3;
Rgba32 rgba = default;
bool anyAlpha = false; bool anyAlpha = false;
using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength))
@ -639,7 +650,7 @@ namespace SixLabors.ImageSharp.Formats.Png
if (quantizedSpan.IndexOf((byte)i) > -1) if (quantizedSpan.IndexOf((byte)i) > -1)
{ {
int offset = i * 3; int offset = i * 3;
palette[i].ToRgba32(ref rgba); var rgba = palette[i].ToRgba32();
byte alpha = rgba.A; byte alpha = rgba.A;
@ -851,7 +862,8 @@ namespace SixLabors.ImageSharp.Formats.Png
/// <param name="source">The source span in 8 bits.</param> /// <param name="source">The source span in 8 bits.</param>
/// <param name="result">The resultant span in <paramref name="bits"/>.</param> /// <param name="result">The resultant span in <paramref name="bits"/>.</param>
/// <param name="bits">The bit depth.</param> /// <param name="bits">The bit depth.</param>
private void ScaleDownFrom8BitArray(ReadOnlySpan<byte> source, Span<byte> result, int bits) /// <param name="scale">The scaling factor.</param>
private void ScaleDownFrom8BitArray(ReadOnlySpan<byte> source, Span<byte> result, int bits, float scale = 1)
{ {
ref byte sourceRef = ref MemoryMarshal.GetReference(source); ref byte sourceRef = ref MemoryMarshal.GetReference(source);
ref byte resultRef = ref MemoryMarshal.GetReference(result); ref byte resultRef = ref MemoryMarshal.GetReference(result);
@ -864,7 +876,7 @@ namespace SixLabors.ImageSharp.Formats.Png
for (int i = 0; i < source.Length; i++) for (int i = 0; i < source.Length; i++)
{ {
int value = Unsafe.Add(ref sourceRef, i) & mask; int value = ((int)MathF.Round(Unsafe.Add(ref sourceRef, i) / scale)) & mask;
v |= value << shift; v |= value << shift;
if (shift == 0) if (shift == 0)

57
src/ImageSharp/Formats/Png/PngScanlineProcessor.cs

@ -32,30 +32,19 @@ namespace SixLabors.ImageSharp.Formats.Png
{ {
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
Rgb48 rgb48 = default;
for (int x = 0, o = 0; x < header.Width; x++, o += 2) for (int x = 0, o = 0; x < header.Width; x++, o += 2)
{ {
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgb48.R = luminance; pixel.PackFromGray16(new Gray16(luminance));
rgb48.G = luminance;
rgb48.B = luminance;
pixel.PackFromRgb48(rgb48);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
} }
} }
else else
{ {
// TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method.
var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = 0; x < header.Width; x++) for (int x = 0; x < header.Width; x++)
{ {
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor);
rgba32.R = luminance; pixel.PackFromGray8(new Gray8(luminance));
rgba32.G = luminance;
rgba32.B = luminance;
pixel.PackFromRgba32(rgba32);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
} }
} }
@ -80,6 +69,7 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
else else
{ {
byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor);
Rgba32 rgba32 = default; Rgba32 rgba32 = default;
for (int x = 0; x < header.Width; x++) for (int x = 0; x < header.Width; x++)
{ {
@ -87,7 +77,7 @@ namespace SixLabors.ImageSharp.Formats.Png
rgba32.R = luminance; rgba32.R = luminance;
rgba32.G = luminance; rgba32.G = luminance;
rgba32.B = luminance; rgba32.B = luminance;
rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue;
pixel.PackFromRgba32(rgba32); pixel.PackFromRgba32(rgba32);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
@ -115,30 +105,19 @@ namespace SixLabors.ImageSharp.Formats.Png
{ {
if (header.BitDepth == 16) if (header.BitDepth == 16)
{ {
Rgb48 rgb48 = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2)
{ {
ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2));
rgb48.R = luminance; pixel.PackFromGray16(new Gray16(luminance));
rgb48.G = luminance;
rgb48.B = luminance;
pixel.PackFromRgb48(rgb48);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
} }
} }
else else
{ {
// TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method.
var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++)
{ {
byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor);
rgba32.R = luminance; pixel.PackFromGray8(new Gray8(luminance));
rgba32.G = luminance;
rgba32.B = luminance;
pixel.PackFromRgba32(rgba32);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
} }
} }
@ -163,6 +142,7 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
else else
{ {
byte scaledLuminanceTrans = (byte)(luminanceTrans * scaleFactor);
Rgba32 rgba32 = default; Rgba32 rgba32 = default;
for (int x = pixelOffset; x < header.Width; x += increment) for (int x = pixelOffset; x < header.Width; x += increment)
{ {
@ -170,7 +150,7 @@ namespace SixLabors.ImageSharp.Formats.Png
rgba32.R = luminance; rgba32.R = luminance;
rgba32.G = luminance; rgba32.G = luminance;
rgba32.B = luminance; rgba32.B = luminance;
rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; rgba32.A = luminance.Equals(scaledLuminanceTrans) ? byte.MinValue : byte.MaxValue;
pixel.PackFromRgba32(rgba32); pixel.PackFromRgba32(rgba32);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
@ -309,14 +289,12 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
else else
{ {
// TODO: We should have PackFromRgb24.
var rgba = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = 0; x < header.Width; x++) for (int x = 0; x < header.Width; x++)
{ {
int index = Unsafe.Add(ref scanlineSpanRef, x); int index = Unsafe.Add(ref scanlineSpanRef, x);
rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index);
pixel.PackFromRgba32(rgba); pixel.PackFromRgb24(rgb);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
} }
} }
@ -356,13 +334,12 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
else else
{ {
var rgba = new Rgba32(0, 0, 0, byte.MaxValue);
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++)
{ {
int index = Unsafe.Add(ref scanlineSpanRef, o); int index = Unsafe.Add(ref scanlineSpanRef, o);
rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); Rgb24 rgb = Unsafe.Add(ref palettePixelsRef, index);
pixel.PackFromRgba32(rgba); pixel.PackFromRgb24(rgb);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
} }
} }
@ -509,14 +486,14 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
else else
{ {
var rgba = new Rgba32(0, 0, 0, byte.MaxValue); Rgb24 rgb = default;
for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel)
{ {
rgba.R = Unsafe.Add(ref scanlineSpanRef, o); rgb.R = Unsafe.Add(ref scanlineSpanRef, o);
rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); rgb.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample);
rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); rgb.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample));
pixel.PackFromRgba32(rgba); pixel.PackFromRgb24(rgb);
Unsafe.Add(ref rowSpanRef, x) = pixel; Unsafe.Add(ref rowSpanRef, x) = pixel;
} }
} }

2
src/ImageSharp/IO/IFileSystem.cs

@ -5,7 +5,6 @@ using System.IO;
namespace SixLabors.ImageSharp.IO namespace SixLabors.ImageSharp.IO
{ {
#if !NETSTANDARD1_1
/// <summary> /// <summary>
/// A simple interface representing the filesystem. /// A simple interface representing the filesystem.
/// </summary> /// </summary>
@ -25,5 +24,4 @@ namespace SixLabors.ImageSharp.IO
/// <returns>A stream representing the file to open.</returns> /// <returns>A stream representing the file to open.</returns>
Stream Create(string path); Stream Create(string path);
} }
#endif
} }

17
src/ImageSharp/IO/LocalFileSystem.cs

@ -1,30 +1,19 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic;
using System.IO; using System.IO;
using System.Text;
namespace SixLabors.ImageSharp.IO namespace SixLabors.ImageSharp.IO
{ {
#if !NETSTANDARD1_1
/// <summary> /// <summary>
/// A wrapper around the local File apis. /// A wrapper around the local File apis.
/// </summary> /// </summary>
internal class LocalFileSystem : IFileSystem internal class LocalFileSystem : IFileSystem
{ {
/// <inheritdoc/> /// <inheritdoc/>
public Stream OpenRead(string path) public Stream OpenRead(string path) => File.OpenRead(path);
{
return File.OpenRead(path);
}
/// <inheritdoc/> /// <inheritdoc/>
public Stream Create(string path) public Stream Create(string path) => File.Create(path);
{
return File.Create(path);
}
} }
#endif }
}

3
src/ImageSharp/Image.FromBytes.cs

@ -174,8 +174,6 @@ namespace SixLabors.ImageSharp
} }
} }
#if !NETSTANDARD1_1
/// <summary> /// <summary>
/// By reading the header on the provided byte array this calculates the images format. /// By reading the header on the provided byte array this calculates the images format.
/// </summary> /// </summary>
@ -303,6 +301,5 @@ namespace SixLabors.ImageSharp
} }
} }
} }
#endif
} }
} }

4
src/ImageSharp/Image.FromFile.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
#if !NETSTANDARD1_1
using System; using System;
using System.IO; using System.IO;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
@ -212,5 +211,4 @@ namespace SixLabors.ImageSharp
} }
} }
} }
} }
#endif

3
src/ImageSharp/ImageExtensions.cs

@ -4,7 +4,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
using System.Text; using System.Text;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats;
@ -17,7 +16,6 @@ namespace SixLabors.ImageSharp
/// </summary> /// </summary>
public static partial class ImageExtensions public static partial class ImageExtensions
{ {
#if !NETSTANDARD1_1
/// <summary> /// <summary>
/// Writes the image to the given stream using the currently loaded image format. /// Writes the image to the given stream using the currently loaded image format.
/// </summary> /// </summary>
@ -78,7 +76,6 @@ namespace SixLabors.ImageSharp
source.Save(fs, encoder); source.Save(fs, encoder);
} }
} }
#endif
/// <summary> /// <summary>
/// Writes the image to the given stream using the currently loaded image format. /// Writes the image to the given stream using the currently loaded image format.

14
src/ImageSharp/ImageFrame{TPixel}.cs

@ -2,8 +2,6 @@
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System; using System;
using System.Buffers;
using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Threading.Tasks; using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
@ -289,22 +287,16 @@ namespace SixLabors.ImageSharp
var target = new ImageFrame<TPixel2>(configuration, this.Width, this.Height, this.MetaData.DeepClone()); var target = new ImageFrame<TPixel2>(configuration, this.Width, this.Height, this.MetaData.DeepClone());
ParallelHelper.IterateRowsWithTempBuffer<Vector4>( ParallelHelper.IterateRows(
this.Bounds(), this.Bounds(),
configuration, configuration,
(rows, tempRowBuffer) => (rows) =>
{ {
for (int y = rows.Min; y < rows.Max; y++) for (int y = rows.Min; y < rows.Max; y++)
{ {
Span<TPixel> sourceRow = this.GetPixelRowSpan(y); Span<TPixel> sourceRow = this.GetPixelRowSpan(y);
Span<TPixel2> targetRow = target.GetPixelRowSpan(y); Span<TPixel2> targetRow = target.GetPixelRowSpan(y);
Span<Vector4> tempRowSpan = tempRowBuffer.Span; PixelOperations<TPixel>.Instance.To(sourceRow, targetRow, sourceRow.Length);
PixelOperations<TPixel>.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length);
PixelOperations<TPixel2>.Instance.PackFromScaledVector4(
tempRowSpan,
targetRow,
targetRow.Length);
} }
}); });

76
src/ImageSharp/ImageSharp.csproj

@ -5,7 +5,7 @@
<VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix> <VersionPrefix Condition="$(packageversion) != ''">$(packageversion)</VersionPrefix>
<VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix> <VersionPrefix Condition="$(packageversion) == ''">0.0.1</VersionPrefix>
<Authors>Six Labors and contributors</Authors> <Authors>Six Labors and contributors</Authors>
<TargetFrameworks>netstandard1.1;netstandard1.3;netstandard2.0;netcoreapp2.1</TargetFrameworks> <TargetFrameworks>netstandard1.3;netstandard2.0;netcoreapp2.1</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<GenerateDocumentationFile>true</GenerateDocumentationFile> <GenerateDocumentationFile>true</GenerateDocumentationFile>
<AssemblyName>SixLabors.ImageSharp</AssemblyName> <AssemblyName>SixLabors.ImageSharp</AssemblyName>
@ -47,7 +47,7 @@
<PackageReference Include="System.IO.UnmanagedMemoryStream" Version="4.3.0" /> <PackageReference Include="System.IO.UnmanagedMemoryStream" Version="4.3.0" />
</ItemGroup> </ItemGroup>
<ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.1' OR '$(TargetFramework)' == 'netstandard1.3'"> <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard1.3'">
<PackageReference Include="System.IO.Compression" Version="4.3.0" /> <PackageReference Include="System.IO.Compression" Version="4.3.0" />
<PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" /> <PackageReference Include="System.Threading.Tasks.Parallel" Version="4.3.0" />
<PackageReference Include="System.ValueTuple" Version="4.5.0" /> <PackageReference Include="System.ValueTuple" Version="4.5.0" />
@ -76,10 +76,42 @@
<Generator>TextTemplatingFileGenerator</Generator> <Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>PixelOperations{TPixel}.Generated.cs</LastGenOutput> <LastGenOutput>PixelOperations{TPixel}.Generated.cs</LastGenOutput>
</None> </None>
<None Update="PixelFormats\Generated\Argb32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Argb32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Bgr24.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Bgr24.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Bgra32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Bgra32.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Gray8.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Gray8.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Gray16.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Gray16.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Rgb24.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgb24.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.tt"> <None Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator> <Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgba32.PixelOperations.Generated.cs</LastGenOutput> <LastGenOutput>Rgba32.PixelOperations.Generated.cs</LastGenOutput>
</None> </None>
<None Update="PixelFormats\Generated\Rgb48.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgb48.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\Generated\Rgba64.PixelOperations.Generated.tt">
<Generator>TextTemplatingFileGenerator</Generator>
<LastGenOutput>Rgba64.PixelOperations.Generated.cs</LastGenOutput>
</None>
<None Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.tt"> <None Update="PixelFormats\PixelBlenders\PorterDuffFunctions.Generated.tt">
<LastGenOutput>PorterDuffFunctions.Generated.cs</LastGenOutput> <LastGenOutput>PorterDuffFunctions.Generated.cs</LastGenOutput>
<Generator>TextTemplatingFileGenerator</Generator> <Generator>TextTemplatingFileGenerator</Generator>
@ -110,11 +142,51 @@
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>PixelOperations{TPixel}.Generated.tt</DependentUpon> <DependentUpon>PixelOperations{TPixel}.Generated.tt</DependentUpon>
</Compile> </Compile>
<Compile Update="PixelFormats\Generated\Argb32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Argb32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Bgr24.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Bgr24.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Bgra32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Bgra32.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Gray8.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Gray8.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Gray16.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Gray16.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Rgb24.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Rgb24.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.cs"> <Compile Update="PixelFormats\Generated\Rgba32.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>
<DependentUpon>Rgba32.PixelOperations.Generated.tt</DependentUpon> <DependentUpon>Rgba32.PixelOperations.Generated.tt</DependentUpon>
</Compile> </Compile>
<Compile Update="PixelFormats\Generated\Rgb48.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Rgb48.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\Generated\Rgba64.PixelOperations.Generated.cs">
<DesignTime>True</DesignTime>
<AutoGen>True</AutoGen>
<DependentUpon>Rgba64.PixelOperations.Generated.tt</DependentUpon>
</Compile>
<Compile Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.cs"> <Compile Update="PixelFormats\PixelBlenders\DefaultPixelBlenders.Generated.cs">
<DesignTime>True</DesignTime> <DesignTime>True</DesignTime>
<AutoGen>True</AutoGen> <AutoGen>True</AutoGen>

2
src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Primitives.cs

@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
} }
Guard.MustBeGreaterThan(length, 0, nameof(length)); Guard.MustBeGreaterThan(length, 0, nameof(length));
string value = AsciiEncoding.GetString(this.data, this.AddIndex(length), length); string value = Encoding.ASCII.GetString(this.data, this.AddIndex(length), length);
// remove data after (potential) null terminator // remove data after (potential) null terminator
int pos = value.IndexOf('\0'); int pos = value.IndexOf('\0');

2
src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs

@ -11,8 +11,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// </summary> /// </summary>
internal sealed partial class IccDataReader internal sealed partial class IccDataReader
{ {
private static readonly Encoding AsciiEncoding = Encoding.GetEncoding("ASCII");
/// <summary> /// <summary>
/// The data that is read /// The data that is read
/// </summary> /// </summary>

4
src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs

@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
return 0; return 0;
} }
byte[] data = AsciiEncoding.GetBytes(value); byte[] data = Encoding.ASCII.GetBytes(value);
this.dataStream.Write(data, 0, data.Length); this.dataStream.Write(data, 0, data.Length);
return data.Length; return data.Length;
} }
@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
value = value.Substring(0, Math.Min(length - lengthAdjust, value.Length)); value = value.Substring(0, Math.Min(length - lengthAdjust, value.Length));
byte[] textData = AsciiEncoding.GetBytes(value); byte[] textData = Encoding.ASCII.GetBytes(value);
int actualLength = Math.Min(length - lengthAdjust, textData.Length); int actualLength = Math.Min(length - lengthAdjust, textData.Length);
this.dataStream.Write(textData, 0, actualLength); this.dataStream.Write(textData, 0, actualLength);
for (int i = 0; i < length - actualLength; i++) for (int i = 0; i < length - actualLength; i++)

6
src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs

@ -3,7 +3,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Text;
namespace SixLabors.ImageSharp.MetaData.Profiles.Icc namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
{ {
@ -12,9 +11,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// </summary> /// </summary>
internal sealed partial class IccDataWriter : IDisposable internal sealed partial class IccDataWriter : IDisposable
{ {
private static readonly bool IsLittleEndian = BitConverter.IsLittleEndian;
private static readonly Encoding AsciiEncoding = Encoding.GetEncoding("ASCII");
/// <summary> /// <summary>
/// The underlying stream where the data is written to /// The underlying stream where the data is written to
/// </summary> /// </summary>
@ -181,7 +177,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <returns>The number of bytes written</returns> /// <returns>The number of bytes written</returns>
private unsafe int WriteBytes(byte* data, int length) private unsafe int WriteBytes(byte* data, int length)
{ {
if (IsLittleEndian) if (BitConverter.IsLittleEndian)
{ {
for (int i = length - 1; i >= 0; i--) for (int i = length - 1; i >= 0; i--)
{ {

9
src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs

@ -3,10 +3,7 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
#if !NETSTANDARD1_1
using System.Security.Cryptography; using System.Security.Cryptography;
#endif
namespace SixLabors.ImageSharp.MetaData.Profiles.Icc namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
{ {
@ -100,8 +97,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public IccProfile DeepClone() => new IccProfile(this); public IccProfile DeepClone() => new IccProfile(this);
#if !NETSTANDARD1_1
/// <summary> /// <summary>
/// Calculates the MD5 hash value of an ICC profile /// Calculates the MD5 hash value of an ICC profile
/// </summary> /// </summary>
@ -147,8 +142,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
} }
} }
#endif
/// <summary> /// <summary>
/// Checks for signs of a corrupt profile. /// Checks for signs of a corrupt profile.
/// </summary> /// </summary>
@ -227,4 +220,4 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
this.entries = new List<IccTagDataEntry>(reader.ReadTagData(this.data)); this.entries = new List<IccTagDataEntry>(reader.ReadTagData(this.data));
} }
} }
} }

5
src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
@ -51,12 +50,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
writer.WriteXyzNumber(header.PcsIlluminant); writer.WriteXyzNumber(header.PcsIlluminant);
writer.WriteAsciiString(header.CreatorSignature, 4, false); writer.WriteAsciiString(header.CreatorSignature, 4, false);
#if !NETSTANDARD1_1
IccProfileId id = IccProfile.CalculateHash(writer.GetData()); IccProfileId id = IccProfile.CalculateHash(writer.GetData());
writer.WriteProfileId(id); writer.WriteProfileId(id);
#else
writer.WriteProfileId(IccProfileId.Zero);
#endif
} }
private void WriteTagTable(IccDataWriter writer, IccTagTableEntry[] table) private void WriteTagTable(IccDataWriter writer, IccTagTableEntry[] table)

4
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs

@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// </summary> /// </summary>
internal sealed class IccDataTagDataEntry : IccTagDataEntry, IEquatable<IccDataTagDataEntry> internal sealed class IccDataTagDataEntry : IccTagDataEntry, IEquatable<IccDataTagDataEntry>
{ {
private static readonly Encoding AsciiEncoding = Encoding.GetEncoding("ASCII");
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="IccDataTagDataEntry"/> class. /// Initializes a new instance of the <see cref="IccDataTagDataEntry"/> class.
/// </summary> /// </summary>
@ -60,7 +58,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// Gets the <see cref="Data"/> decoded as 7bit ASCII. /// Gets the <see cref="Data"/> decoded as 7bit ASCII.
/// If <see cref="IsAscii"/> is false, returns null /// If <see cref="IsAscii"/> is false, returns null
/// </summary> /// </summary>
public string AsciiString => this.IsAscii ? AsciiEncoding.GetString(this.Data, 0, this.Data.Length) : null; public string AsciiString => this.IsAscii ? Encoding.ASCII.GetString(this.Data, 0, this.Data.Length) : null;
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(IccTagDataEntry other) public override bool Equals(IccTagDataEntry other)

171
src/ImageSharp/PixelFormats/Alpha8.cs

@ -18,11 +18,14 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Alpha8"/> struct. /// Initializes a new instance of the <see cref="Alpha8"/> struct.
/// </summary> /// </summary>
/// <param name="alpha">The alpha component</param> /// <param name="alpha">The alpha component.</param>
public Alpha8(float alpha) public Alpha8(byte alpha) => this.PackedValue = alpha;
{
this.PackedValue = Pack(alpha); /// <summary>
} /// Initializes a new instance of the <see cref="Alpha8"/> struct.
/// </summary>
/// <param name="alpha">The alpha component.</param>
public Alpha8(float alpha) => this.PackedValue = Pack(alpha);
/// <inheritdoc /> /// <inheritdoc />
public byte PackedValue { get; set; } public byte PackedValue { get; set; }
@ -39,11 +42,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Alpha8 left, Alpha8 right) public static bool operator ==(Alpha8 left, Alpha8 right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="Alpha8"/> objects for equality. /// Compares two <see cref="Alpha8"/> objects for equality.
@ -53,161 +53,91 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Alpha8 left, Alpha8 right) public static bool operator !=(Alpha8 left, Alpha8 right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<Alpha8> CreatePixelOperations() => new PixelOperations<Alpha8>(); public PixelOperations<Alpha8> CreatePixelOperations() => new PixelOperations<Alpha8>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
this.PackFromVector4(vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4() => this.ToVector4();
{
return this.ToVector4();
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W);
{
this.PackedValue = Pack(vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4() => new Vector4(0, 0, 0, this.PackedValue / 255F);
{
return new Vector4(0, 0, 0, this.PackedValue / 255F);
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackedValue = source.A;
{
this.PackedValue = source.A;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue;
{
this.PackedValue = source.A;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackedValue = source.A;
{
this.PackedValue = source.A;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackedValue = byte.MaxValue;
{
dest = default(Rgb24);
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackedValue = byte.MaxValue;
{
dest.R = 0;
dest.G = 0;
dest.B = 0;
dest.A = this.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue;
{
dest.R = 0;
dest.G = 0;
dest.B = 0;
dest.A = this.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackedValue = source.A;
{
dest = default(Bgr24);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(0, 0, 0, this.PackedValue);
{
dest.R = 0;
dest.G = 0;
dest.B = 0;
dest.A = this.PackedValue;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; public void PackFromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest)
{
dest.R = 0;
dest.G = 0;
dest.B = 0;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <summary> /// <summary>
/// Compares an object with the packed vector. /// Compares an object with the packed vector.
/// </summary> /// </summary>
/// <param name="obj">The object to compare.</param> /// <param name="obj">The object to compare.</param>
/// <returns>True if the object is equal to the packed vector.</returns> /// <returns>True if the object is equal to the packed vector.</returns>
public override bool Equals(object obj) public override bool Equals(object obj) => obj is Alpha8 other && this.Equals(other);
{
return obj is Alpha8 other && this.Equals(other);
}
/// <summary> /// <summary>
/// Compares another Alpha8 packed vector with the packed vector. /// Compares another Alpha8 packed vector with the packed vector.
/// </summary> /// </summary>
/// <param name="other">The Alpha8 packed vector to compare.</param> /// <param name="other">The Alpha8 packed vector to compare.</param>
/// <returns>True if the packed vectors are equal.</returns> /// <returns>True if the packed vectors are equal.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Alpha8 other) public bool Equals(Alpha8 other) => this.PackedValue.Equals(other.PackedValue);
{
return this.PackedValue == other.PackedValue;
}
/// <summary> /// <summary>
/// Gets a string representation of the packed vector. /// Gets a string representation of the packed vector.
/// </summary> /// </summary>
/// <returns>A string representation of the packed vector.</returns> /// <returns>A string representation of the packed vector.</returns>
public override string ToString() public override string ToString() => $"Alpha8({this.PackedValue})";
{
return (this.PackedValue / 255F).ToString();
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode(); public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary> /// <summary>
@ -215,10 +145,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
/// <param name="alpha">The float containing the value to pack.</param> /// <param name="alpha">The float containing the value to pack.</param>
/// <returns>The <see cref="byte"/> containing the packed values.</returns> /// <returns>The <see cref="byte"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
private static byte Pack(float alpha) private static byte Pack(float alpha) => (byte)Math.Round(alpha.Clamp(0, 1F) * 255F);
{
return (byte)Math.Round(alpha.Clamp(0, 1) * 255F);
}
} }
} }

253
src/ImageSharp/PixelFormats/Argb32.cs

@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// as it avoids the need to create new values for modification operations. /// as it avoids the need to create new values for modification operations.
/// </remarks> /// </remarks>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Argb32 : IPixel<Argb32>, IPackedVector<uint> public partial struct Argb32 : IPixel<Argb32>, IPackedVector<uint>
{ {
/// <summary> /// <summary>
/// Gets or sets the alpha component. /// Gets or sets the alpha component.
@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="r">The red component.</param> /// <param name="r">The red component.</param>
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Argb32(byte r, byte g, byte b) public Argb32(byte r, byte g, byte b)
{ {
this.R = r; this.R = r;
@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param> /// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Argb32(byte r, byte g, byte b, byte a) public Argb32(byte r, byte g, byte b, byte a)
{ {
this.R = r; this.R = r;
@ -89,12 +89,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param> /// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Argb32(float r, float g, float b, float a = 1) public Argb32(float r, float g, float b, float a = 1)
: this() : this() => this.Pack(r, g, b, a);
{
this.Pack(r, g, b, a);
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct. /// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -102,12 +99,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector"> /// <param name="vector">
/// The vector containing the components for the packed vector. /// The vector containing the components for the packed vector.
/// </param> /// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Argb32(Vector3 vector) public Argb32(Vector3 vector)
: this() : this() => this.Pack(ref vector);
{
this.Pack(ref vector);
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct. /// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -115,12 +109,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector"> /// <param name="vector">
/// The vector containing the components for the packed vector. /// The vector containing the components for the packed vector.
/// </param> /// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Argb32(Vector4 vector) public Argb32(Vector4 vector)
: this() : this() => this.Pack(ref vector);
{
this.Pack(ref vector);
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Argb32"/> struct. /// Initializes a new instance of the <see cref="Argb32"/> struct.
@ -128,22 +119,19 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="packed"> /// <param name="packed">
/// The packed value. /// The packed value.
/// </param> /// </param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Argb32(uint packed) public Argb32(uint packed)
: this() : this() => this.Argb = packed;
{
this.Argb = packed;
}
/// <summary> /// <summary>
/// Gets or sets the packed representation of the Argb32 struct. /// Gets or sets the packed representation of the Argb32 struct.
/// </summary> /// </summary>
public uint Argb public uint Argb
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
get => Unsafe.As<Argb32, uint>(ref this); get => Unsafe.As<Argb32, uint>(ref this);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Argb32, uint>(ref this) = value; set => Unsafe.As<Argb32, uint>(ref this) = value;
} }
@ -157,20 +145,13 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Compares two <see cref="Argb32"/> objects for equality. /// Compares two <see cref="Argb32"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="Argb32"/> on the left side of the operand.</param>
/// The <see cref="Argb32"/> on the left side of the operand. /// <param name="right">The <see cref="Argb32"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="Argb32"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Argb32 left, Argb32 right) public static bool operator ==(Argb32 left, Argb32 right) => left.Equals(right);
{
return left.Argb == right.Argb;
}
/// <summary> /// <summary>
/// Compares two <see cref="Argb32"/> objects for equality. /// Compares two <see cref="Argb32"/> objects for equality.
@ -180,62 +161,44 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Argb32 left, Argb32 right) public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right);
{
return left.Argb != right.Argb; /// <inheritdoc />
} public PixelOperations<Argb32> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
this.Pack(ref vector);
}
/// <inheritdoc /> /// <inheritdoc/>
public PixelOperations<Argb32> CreatePixelOperations() => new PixelOperations<Argb32>(); [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromVector4(Vector4 vector) => this.Pack(ref vector);
{
this.PackFromVector4(vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
{
return this.ToVector4();
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public void PackFromArgb32(Argb32 source) => this.PackedValue = source.PackedValue;
{
return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromBgr24(Bgr24 source)
{ {
this.R = source.R; this.R = source.R;
this.G = source.G; this.G = source.G;
this.B = source.B; this.B = source.B;
this.A = source.A; this.A = byte.MaxValue;
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
this.PackedValue = source.PackedValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source)
{ {
this.R = source.R; this.R = source.R;
@ -244,136 +207,88 @@ namespace SixLabors.ImageSharp.PixelFormats
this.A = source.A; this.A = source.A;
} }
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source)
{ {
dest.R = this.R; this.R = source.PackedValue;
dest.G = this.G; this.G = source.PackedValue;
dest.B = this.B; this.B = source.PackedValue;
this.A = byte.MaxValue;
} }
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source)
{ {
dest.R = this.R; byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
dest.G = this.G; this.R = rgb;
dest.B = this.B; this.G = rgb;
dest.A = this.A; this.B = rgb;
this.A = byte.MaxValue;
} }
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source)
{ {
dest = this; this.R = source.R;
this.G = source.G;
this.B = source.B;
this.A = byte.MaxValue;
} }
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source)
{ {
dest.R = this.R; this.R = source.R;
dest.G = this.G; this.G = source.G;
dest.B = this.B; this.B = source.B;
this.A = source.A;
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = this.A;
}
/// <summary>
/// Converts the pixel to <see cref="Rgba32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A);
/// <summary>
/// Converts the pixel to <see cref="Bgra32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Bgra32 ToBgra32() => new Bgra32(this.R, this.G, this.B, this.A);
/// <summary>
/// Converts the pixel to <see cref="Argb32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32 ToArgb32() => this;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) public void PackFromRgb48(Rgb48 source)
{ {
this.R = (byte)(((source.R * 255) + 32895) >> 16); this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = (byte)(((source.G * 255) + 32895) >> 16); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = (byte)(((source.B * 255) + 32895) >> 16); this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = byte.MaxValue; this.A = byte.MaxValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) public void PackFromRgba64(Rgba64 source)
{ {
this.R = (byte)(((source.R * 255) + 32895) >> 16); this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = (byte)(((source.G * 255) + 32895) >> 16); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = (byte)(((source.B * 255) + 32895) >> 16); this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = (byte)(((source.A * 255) + 32895) >> 16); this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) => obj is Argb32 argb32 && this.Equals(argb32);
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
public override bool Equals(object obj)
{
return obj is Argb32 argb32 && this.Equals(argb32);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Argb32 other) public bool Equals(Argb32 other) => this.Argb == other.Argb;
{
return this.Argb == other.Argb;
}
/// <summary> /// <summary>
/// Gets a string representation of the packed vector. /// Gets a string representation of the packed vector.
/// </summary> /// </summary>
/// <returns>A string representation of the packed vector.</returns> /// <returns>A string representation of the packed vector.</returns>
public override string ToString() public override string ToString() => $"Argb({this.A}, {this.R}, {this.G}, {this.B})";
{
return $"({this.R},{this.G},{this.B},{this.A})";
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.Argb.GetHashCode(); public override int GetHashCode() => this.Argb.GetHashCode();
/// <summary>
/// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1]
/// </summary>
/// <returns>A <see cref="Vector4"/> of values in [0, 255] </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal Vector4 ToByteScaledVector4()
{
return new Vector4(this.R, this.G, this.B, this.A);
}
/// <summary> /// <summary>
/// Packs the four floats into a color. /// Packs the four floats into a color.
/// </summary> /// </summary>
@ -381,7 +296,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="y">The y-component</param> /// <param name="y">The y-component</param>
/// <param name="z">The z-component</param> /// <param name="z">The z-component</param>
/// <param name="w">The w-component</param> /// <param name="w">The w-component</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
private void Pack(float x, float y, float z, float w) private void Pack(float x, float y, float z, float w)
{ {
var value = new Vector4(x, y, z, w); var value = new Vector4(x, y, z, w);
@ -392,7 +307,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Packs a <see cref="Vector3"/> into a uint. /// Packs a <see cref="Vector3"/> into a uint.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the values to pack.</param> /// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector3 vector) private void Pack(ref Vector3 vector)
{ {
var value = new Vector4(vector, 1); var value = new Vector4(vector, 1);
@ -403,7 +318,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// Packs a <see cref="Vector4"/> into a color. /// Packs a <see cref="Vector4"/> into a color.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the values to pack.</param> /// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector4 vector) private void Pack(ref Vector4 vector)
{ {
vector *= MaxBytes; vector *= MaxBytes;

179
src/ImageSharp/PixelFormats/Bgr24.cs

@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </para> /// </para>
/// </summary> /// </summary>
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct Bgr24 : IPixel<Bgr24> public partial struct Bgr24 : IPixel<Bgr24>
{ {
/// <summary> /// <summary>
/// The blue component. /// The blue component.
@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="r">The red component.</param> /// <param name="r">The red component.</param>
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Bgr24(byte r, byte g, byte b) public Bgr24(byte r, byte g, byte b)
{ {
this.R = r; this.R = r;
@ -49,39 +49,54 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = b; this.B = b;
} }
/// <summary>
/// Compares two <see cref="Bgr24"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Bgr24"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Bgr24"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Bgr24 left, Bgr24 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Bgr24"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Bgr24"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Bgr24"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right);
/// <inheritdoc/> /// <inheritdoc/>
public PixelOperations<Bgr24> CreatePixelOperations() => new PixelOperations<Bgr24>(); public PixelOperations<Bgr24> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Bgr24 other) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
return this.R == other.R && this.G == other.G && this.B == other.B;
}
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) [MethodImpl(InliningOptions.ShortMethod)]
{ public Vector4 ToScaledVector4() => this.ToVector4();
return obj is Bgr24 other && this.Equals(other);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() public void PackFromVector4(Vector4 vector)
{ {
int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode()); Rgba32 rgba = default;
return HashHelpers.Combine(hash, this.B.GetHashCode()); rgba.PackFromVector4(vector);
this.PackFromRgba32(rgba);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4();
{
this = source.Bgr;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromArgb32(Argb32 source)
{ {
this.R = source.R; this.R = source.R;
@ -90,7 +105,11 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this = source;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source)
{ {
this.R = source.R; this.R = source.R;
@ -99,109 +118,75 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromGray8(Gray8 source)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{ {
return this.ToVector4(); this.R = source.PackedValue;
this.G = source.PackedValue;
this.B = source.PackedValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromGray16(Gray16 source)
{ {
Rgba32 rgba = default; byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
rgba.PackFromVector4(vector); this.R = rgb;
this.PackFromRgba32(rgba); this.G = rgb;
this.B = rgb;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public void PackFromRgb24(Rgb24 source)
{ {
return new Rgba32(this.R, this.G, this.B, 255).ToVector4(); this.R = source.R;
} this.G = source.G;
this.B = source.B;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromRgba32(Rgba32 source) => this = source.Bgr;
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = byte.MaxValue;
}
/// <inheritdoc/> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue);
{
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = byte.MaxValue;
}
/// <inheritdoc/> /// <inheritdoc/>
public void ToBgr24(ref Bgr24 dest) [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
{ {
dest = this; this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
} }
/// <inheritdoc/> /// <inheritdoc/>
public void ToBgra32(ref Bgra32 dest) [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source)
{ {
dest.R = this.R; this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
dest.G = this.G; this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
dest.B = this.B; this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
dest.A = byte.MaxValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) public bool Equals(Bgr24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) => obj is Bgr24 other && this.Equals(other);
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() => $"Bgra({this.B}, {this.G}, {this.R})";
public void PackFromRgba64(Rgba64 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); public override int GetHashCode()
/// <inheritdoc />
public override string ToString()
{ {
return $"({this.B},{this.G},{this.R})"; int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
return HashHelpers.Combine(hash, this.B.GetHashCode());
} }
} }
} }

204
src/ImageSharp/PixelFormats/Bgr565.cs

@ -8,7 +8,8 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats namespace SixLabors.ImageSharp.PixelFormats
{ {
/// <summary> /// <summary>
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x and z components use 5 bits, and the y component uses 6 bits. /// Packed pixel type containing unsigned normalized values ranging from 0 to 1.
/// The x and z components use 5 bits, and the y component uses 6 bits.
/// <para> /// <para>
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para> /// </para>
@ -22,8 +23,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="y">The y-component</param> /// <param name="y">The y-component</param>
/// <param name="z">The z-component</param> /// <param name="z">The z-component</param>
public Bgr565(float x, float y, float z) public Bgr565(float x, float y, float z)
: this(new Vector3(x, y, z))
{ {
this.PackedValue = Pack(x, y, z);
} }
/// <summary> /// <summary>
@ -32,10 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector"> /// <param name="vector">
/// The vector containing the components for the packed value. /// The vector containing the components for the packed value.
/// </param> /// </param>
public Bgr565(Vector3 vector) public Bgr565(Vector3 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z);
}
/// <inheritdoc/> /// <inheritdoc/>
public ushort PackedValue { get; set; } public ushort PackedValue { get; set; }
@ -48,11 +46,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Bgr565 left, Bgr565 right) public static bool operator ==(Bgr565 left, Bgr565 right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="Bgr565"/> objects for equality. /// Compares two <see cref="Bgr565"/> objects for equality.
@ -62,183 +57,112 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgr565 left, Bgr565 right) public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<Bgr565> CreatePixelOperations() => new PixelOperations<Bgr565>(); public PixelOperations<Bgr565> CreatePixelOperations() => new PixelOperations<Bgr565>();
/// <summary>
/// Expands the packed representation into a <see cref="Vector3"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector3"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector3 ToVector3()
{
return new Vector3(
((this.PackedValue >> 11) & 0x1F) * (1F / 31F),
((this.PackedValue >> 5) & 0x3F) * (1F / 63F),
(this.PackedValue & 0x1F) * (1F / 31F));
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
this.PackFromVector4(vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4() => this.ToVector4();
{
return this.ToVector4();
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector)
{ {
this.PackedValue = Pack(vector.X, vector.Y, vector.Z); var vector3 = new Vector3(vector.X, vector.Y, vector.Z);
this.PackedValue = Pack(ref vector3);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4() => new Vector4(this.ToVector3(), 1F);
{
return new Vector4(this.ToVector3(), 1F); /// <inheritdoc/>
} [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackFromVector4(source.ToVector4());
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromVector4(source.ToVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb24(ref Rgb24 dest)
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromVector4(source.ToVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// Expands the packed representation into a <see cref="Vector3"/>.
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <inheritdoc /> /// <returns>The <see cref="Vector3"/>.</returns>
public override bool Equals(object obj) [MethodImpl(InliningOptions.ShortMethod)]
public Vector3 ToVector3()
{ {
return obj is Bgr565 other && this.Equals(other); return new Vector3(
((this.PackedValue >> 11) & 0x1F) * (1F / 31F),
((this.PackedValue >> 5) & 0x3F) * (1F / 63F),
(this.PackedValue & 0x1F) * (1F / 31F));
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) => obj is Bgr565 other && this.Equals(other);
public bool Equals(Bgr565 other)
{ /// <inheritdoc />
return this.PackedValue == other.PackedValue; [MethodImpl(InliningOptions.ShortMethod)]
} public bool Equals(Bgr565 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return this.ToVector3().ToString(); var vector = this.ToVector3();
return FormattableString.Invariant($"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})");
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode(); public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary> [MethodImpl(InliningOptions.ShortMethod)]
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>. private static ushort Pack(ref Vector3 vector)
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(float x, float y, float z)
{ {
return (ushort)((((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 11) vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One);
| (((int)Math.Round(y.Clamp(0, 1) * 63F) & 0x3F) << 5)
| ((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F)); return (ushort)((((int)Math.Round(vector.X * 31F) & 0x1F) << 11)
| (((int)Math.Round(vector.Y * 63F) & 0x3F) << 5)
| ((int)Math.Round(vector.Z * 31F) & 0x1F));
} }
} }
} }

210
src/ImageSharp/PixelFormats/Bgra32.cs

@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </para> /// </para>
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint> public partial struct Bgra32 : IPixel<Bgra32>, IPackedVector<uint>
{ {
/// <summary> /// <summary>
/// Gets or sets the blue component. /// Gets or sets the blue component.
@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="r">The red component.</param> /// <param name="r">The red component.</param>
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Bgra32(byte r, byte g, byte b) public Bgra32(byte r, byte g, byte b)
{ {
this.R = r; this.R = r;
@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
/// <param name="a">The alpha component.</param> /// <param name="a">The alpha component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Bgra32(byte r, byte g, byte b, byte a) public Bgra32(byte r, byte g, byte b, byte a)
{ {
this.R = r; this.R = r;
@ -84,10 +84,10 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public uint Bgra public uint Bgra
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
get => Unsafe.As<Bgra32, uint>(ref this); get => Unsafe.As<Bgra32, uint>(ref this);
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
set => Unsafe.As<Bgra32, uint>(ref this) = value; set => Unsafe.As<Bgra32, uint>(ref this) = value;
} }
@ -98,62 +98,50 @@ namespace SixLabors.ImageSharp.PixelFormats
set => this.Bgra = value; set => this.Bgra = value;
} }
/// <inheritdoc/> /// <summary>
public PixelOperations<Bgra32> CreatePixelOperations() => new PixelOperations<Bgra32>(); /// Compares two <see cref="Bgra32"/> objects for equality.
/// </summary>
/// <inheritdoc/> /// <param name="left">The <see cref="Bgra32"/> on the left side of the operand.</param>
public bool Equals(Bgra32 other) /// <param name="right">The <see cref="Bgra32"/> on the right side of the operand.</param>
{ /// <returns>
return this.Bgra == other.Bgra; /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
} /// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
/// <inheritdoc/> public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right);
public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other);
/// <inheritdoc/>
public override int GetHashCode() => this.Bgra.GetHashCode();
/// <summary> /// <summary>
/// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1] /// Compares two <see cref="Bgra32"/> objects for equality.
/// </summary> /// </summary>
/// <returns>A <see cref="Vector4"/> of values in [0, 255] </returns> /// <param name="left">The <see cref="Bgra32"/> on the left side of the operand.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// <param name="right">The <see cref="Bgra32"/> on the right side of the operand.</param>
internal Vector4 ToByteScaledVector4() /// <returns>
{ /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
return new Vector4(this.R, this.G, this.B, this.A); /// </returns>
} [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right);
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] public PixelOperations<Bgra32> CreatePixelOperations() => new PixelOperations();
public void PackFromScaledVector4(Vector4 vector)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
return this.ToVector4();
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public Vector4 ToScaledVector4() => this.ToVector4();
{
this.Pack(ref vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public void PackFromVector4(Vector4 vector) => this.Pack(ref vector);
{
return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{ {
this.R = source.R; this.R = source.R;
this.G = source.G; this.G = source.G;
@ -162,113 +150,101 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source)
{ {
this.R = source.R; this.R = source.R;
this.G = source.G; this.G = source.G;
this.B = source.B; this.B = source.B;
this.A = source.A; this.A = byte.MaxValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this = source;
{
this.PackedValue = source.PackedValue;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source)
{ {
dest.R = this.R; this.R = source.PackedValue;
dest.G = this.G; this.G = source.PackedValue;
dest.B = this.B; this.B = source.PackedValue;
this.A = byte.MaxValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source)
{ {
dest.R = this.R; byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
dest.G = this.G; this.R = rgb;
dest.B = this.B; this.G = rgb;
dest.A = this.A; this.B = rgb;
this.A = byte.MaxValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgba32(Rgba32 source)
{ {
dest.R = this.R; this.R = source.R;
dest.G = this.G; this.G = source.G;
dest.B = this.B; this.B = source.B;
dest.A = this.A; this.A = source.A;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) => dest = Unsafe.As<Bgra32, Bgr24>(ref this); public void PackFromRgb24(Rgb24 source)
{
/// <inheritdoc/> this.R = source.R;
[MethodImpl(MethodImplOptions.AggressiveInlining)] this.G = source.G;
public void ToBgra32(ref Bgra32 dest) => dest = this; this.B = source.B;
this.A = byte.MaxValue;
}
/// <summary> /// <inheritdoc />
/// Converts the pixel to <see cref="Rgba32"/> format. [MethodImpl(InliningOptions.ShortMethod)]
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A); public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, this.A);
/// <summary>
/// Converts the pixel to <see cref="Argb32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Argb32 ToArgb32() => new Argb32(this.R, this.G, this.B, this.A);
/// <summary>
/// Converts the pixel to <see cref="Bgra32"/> format.
/// </summary>
/// <returns>The RGBA value</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Bgra32 ToBgra32() => this;
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) public void PackFromRgb48(Rgb48 source)
{ {
this.R = (byte)(((source.R * 255) + 32895) >> 16); this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = (byte)(((source.G * 255) + 32895) >> 16); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = (byte)(((source.B * 255) + 32895) >> 16); this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = byte.MaxValue; this.A = byte.MaxValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) public void PackFromRgba64(Rgba64 source)
{ {
this.R = (byte)(((source.R * 255) + 32895) >> 16); this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
this.G = (byte)(((source.G * 255) + 32895) >> 16); this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
this.B = (byte)(((source.B * 255) + 32895) >> 16); this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
this.A = (byte)(((source.A * 255) + 32895) >> 16); this.A = ImageMaths.DownScaleFrom16BitTo8Bit(source.A);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other);
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
public bool Equals(Bgra32 other) => this.Bgra.Equals(other.Bgra);
/// <inheritdoc/>
public override int GetHashCode() => this.Bgra.GetHashCode();
/// <inheritdoc />
public override string ToString() => $"Bgra32({this.B}, {this.G}, {this.R}, {this.A})";
/// <summary> /// <summary>
/// Packs a <see cref="Vector4"/> into a color. /// Packs a <see cref="Vector4"/> into a color.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the values to pack.</param> /// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector4 vector) private void Pack(ref Vector4 vector)
{ {
vector *= MaxBytes; vector *= MaxBytes;
@ -280,11 +256,5 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = (byte)vector.Z; this.B = (byte)vector.Z;
this.A = (byte)vector.W; this.A = (byte)vector.W;
} }
/// <inheritdoc />
public override string ToString()
{
return $"({this.B},{this.G},{this.R},{this.A})";
}
} }
} }

186
src/ImageSharp/PixelFormats/Bgra4444.cs

@ -23,18 +23,15 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component</param> /// <param name="z">The z-component</param>
/// <param name="w">The w-component</param> /// <param name="w">The w-component</param>
public Bgra4444(float x, float y, float z, float w) public Bgra4444(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{ {
this.PackedValue = Pack(x, y, z, w);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Bgra4444"/> struct. /// Initializes a new instance of the <see cref="Bgra4444"/> struct.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the components for the packed vector.</param> /// <param name="vector">The vector containing the components for the packed vector.</param>
public Bgra4444(Vector4 vector) public Bgra4444(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <inheritdoc/> /// <inheritdoc/>
public ushort PackedValue { get; set; } public ushort PackedValue { get; set; }
@ -47,11 +44,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Bgra4444 left, Bgra4444 right) public static bool operator ==(Bgra4444 left, Bgra4444 right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="Bgra4444"/> objects for equality. /// Compares two <see cref="Bgra4444"/> objects for equality.
@ -61,177 +55,103 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgra4444 left, Bgra4444 right) public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<Bgra4444> CreatePixelOperations() => new PixelOperations<Bgra4444>(); public PixelOperations<Bgra4444> CreatePixelOperations() => new PixelOperations<Bgra4444>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
this.PackFromVector4(vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4() => this.ToVector4();
{
return this.ToVector4();
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4()
{ {
const float Max = 1 / 15F; const float Max = 1 / 15F;
return new Vector4( return new Vector4(
((this.PackedValue >> 8) & 0x0F) * Max, (this.PackedValue >> 8) & 0x0F,
((this.PackedValue >> 4) & 0x0F) * Max, (this.PackedValue >> 4) & 0x0F,
(this.PackedValue & 0x0F) * Max, this.PackedValue & 0x0F,
((this.PackedValue >> 12) & 0x0F) * Max); (this.PackedValue >> 12) & 0x0F) * Max;
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba32(Rgba32 source)
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is Bgra4444 other && this.Equals(other);
{
return obj is Bgra4444 other && this.Equals(other);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Bgra4444 other) public bool Equals(Bgra4444 other) => this.PackedValue.Equals(other.PackedValue);
{
return this.PackedValue == other.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return this.ToVector4().ToString(); var vector = this.ToVector4();
return FormattableString.Invariant($"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})");
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode(); public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary> [MethodImpl(InliningOptions.ShortMethod)]
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>. private static ushort Pack(ref Vector4 vector)
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(float x, float y, float z, float w)
{ {
return (ushort)((((int)Math.Round(w.Clamp(0, 1) * 15F) & 0x0F) << 12) | vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One);
(((int)Math.Round(x.Clamp(0, 1) * 15F) & 0x0F) << 8) | return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12)
(((int)Math.Round(y.Clamp(0, 1) * 15F) & 0x0F) << 4) | | (((int)Math.Round(vector.X * 15F) & 0x0F) << 8)
((int)Math.Round(z.Clamp(0, 1) * 15F) & 0x0F)); | (((int)Math.Round(vector.Y * 15F) & 0x0F) << 4)
| ((int)Math.Round(vector.Z * 15F) & 0x0F));
} }
} }
} }

194
src/ImageSharp/PixelFormats/Bgra5551.cs

@ -8,7 +8,8 @@ using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats namespace SixLabors.ImageSharp.PixelFormats
{ {
/// <summary> /// <summary>
/// Packed pixel type containing unsigned normalized values ranging from 0 to 1. The x , y and z components use 5 bits, and the w component uses 1 bit. /// Packed pixel type containing unsigned normalized values ranging from 0 to 1.
/// The x , y and z components use 5 bits, and the w component uses 1 bit.
/// <para> /// <para>
/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form.
/// </para> /// </para>
@ -23,8 +24,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component</param> /// <param name="z">The z-component</param>
/// <param name="w">The w-component</param> /// <param name="w">The w-component</param>
public Bgra5551(float x, float y, float z, float w) public Bgra5551(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{ {
this.PackedValue = Pack(x, y, z, w);
} }
/// <summary> /// <summary>
@ -33,10 +34,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector"> /// <param name="vector">
/// The vector containing the components for the packed vector. /// The vector containing the components for the packed vector.
/// </param> /// </param>
public Bgra5551(Vector4 vector) public Bgra5551(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <inheritdoc/> /// <inheritdoc/>
public ushort PackedValue { get; set; } public ushort PackedValue { get; set; }
@ -49,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Bgra5551 left, Bgra5551 right) public static bool operator ==(Bgra5551 left, Bgra5551 right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="Bgra5551"/> objects for equality. /// Compares two <see cref="Bgra5551"/> objects for equality.
@ -63,31 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Bgra5551 left, Bgra5551 right) public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<Bgra5551> CreatePixelOperations() => new PixelOperations<Bgra5551>(); public PixelOperations<Bgra5551> CreatePixelOperations() => new PixelOperations<Bgra5551>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
this.PackFromVector4(vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4() => this.ToVector4();
{
return this.ToVector4(); /// <inheritdoc />
} [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4()
{ {
return new Vector4( return new Vector4(
@ -98,150 +88,72 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is Bgra5551 other && this.Equals(other);
{
return obj is Bgra5551 other && this.Equals(other);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Bgra5551 other) public bool Equals(Bgra5551 other) => this.PackedValue.Equals(other.PackedValue);
{
return this.PackedValue == other.PackedValue;
}
/// <summary> /// <inheritdoc />
/// Gets a string representation of the packed vector.
/// </summary>
/// <returns>A string representation of the packed vector.</returns>
public override string ToString() public override string ToString()
{ {
return this.ToVector4().ToString(); var vector = this.ToVector4();
return FormattableString.Invariant($"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})");
} }
/// <summary> /// <inheritdoc />
/// Gets a hash code of the packed vector. [MethodImpl(InliningOptions.ShortMethod)]
/// </summary>
/// <returns>The hash code for the packed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => this.PackedValue.GetHashCode(); public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary> [MethodImpl(InliningOptions.ShortMethod)]
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>. private static ushort Pack(ref Vector4 vector)
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(float x, float y, float z, float w)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One);
return (ushort)( return (ushort)(
(((int)Math.Round(x.Clamp(0, 1) * 31F) & 0x1F) << 10) (((int)Math.Round(vector.X * 31F) & 0x1F) << 10)
| (((int)Math.Round(y.Clamp(0, 1) * 31F) & 0x1F) << 5) | (((int)Math.Round(vector.Y * 31F) & 0x1F) << 5)
| (((int)Math.Round(z.Clamp(0, 1) * 31F) & 0x1F) << 0) | (((int)Math.Round(vector.Z * 31F) & 0x1F) << 0)
| (((int)Math.Round(w.Clamp(0, 1)) & 0x1) << 15)); | (((int)Math.Round(vector.W) & 0x1) << 15));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4() => this.ToVector4() * 255f;
} }
} }

168
src/ImageSharp/PixelFormats/Byte4.cs

@ -21,10 +21,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="vector"> /// <param name="vector">
/// A vector containing the initial values for the components of the Byte4 structure. /// A vector containing the initial values for the components of the Byte4 structure.
/// </param> /// </param>
public Byte4(Vector4 vector) public Byte4(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(ref vector);
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Byte4"/> struct. /// Initializes a new instance of the <see cref="Byte4"/> struct.
@ -50,11 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Byte4 left, Byte4 right) public static bool operator ==(Byte4 left, Byte4 right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="Byte4"/> objects for equality. /// Compares two <see cref="Byte4"/> objects for equality.
@ -64,38 +58,26 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Byte4 left, Byte4 right) public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<Byte4> CreatePixelOperations() => new PixelOperations<Byte4>(); public PixelOperations<Byte4> CreatePixelOperations() => new PixelOperations<Byte4>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector * 255F);
{
this.PackFromVector4(vector * 255F);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4() => this.ToVector4() / 255F;
{
return this.ToVector4() / 255F;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(ref vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4()
{ {
return new Vector4( return new Vector4(
@ -106,119 +88,61 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToByteScaledVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToByteScaledVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToByteScaledVector4());
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
var vector = this.ToVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is Byte4 byte4 && this.Equals(byte4);
{
return obj is Byte4 byte4 && this.Equals(byte4);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Byte4 other) public bool Equals(Byte4 other) => this.PackedValue.Equals(other.PackedValue);
{
return this == other;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode(); public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <summary> /// <inheritdoc />
/// Returns a string representation of the current instance.
/// </summary>
/// <returns>String that represents the object.</returns>
public override string ToString() public override string ToString()
{ {
return this.PackedValue.ToString("x8"); var vector = this.ToVector4();
return FormattableString.Invariant($"Bgra5551({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
} }
/// <summary> /// <summary>
@ -226,18 +150,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
/// <param name="vector">The vector containing the values to pack.</param> /// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns> /// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
private static uint Pack(ref Vector4 vector) private static uint Pack(ref Vector4 vector)
{ {
const float Max = 255F; const float Max = 255F;
const float Min = 0F;
// Clamp the value between min and max values // Clamp the value between min and max values
// TODO: Use Vector4.Clamp() here! vector = Vector4.Clamp(vector, Vector4.Zero, new Vector4(Max));
uint byte4 = (uint)Math.Round(vector.X.Clamp(Min, Max)) & 0xFF;
uint byte3 = ((uint)Math.Round(vector.Y.Clamp(Min, Max)) & 0xFF) << 0x8; uint byte4 = (uint)Math.Round(vector.X) & 0xFF;
uint byte2 = ((uint)Math.Round(vector.Z.Clamp(Min, Max)) & 0xFF) << 0x10; uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8;
uint byte1 = ((uint)Math.Round(vector.W.Clamp(Min, Max)) & 0xFF) << 0x18; uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 0x10;
uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 0x18;
return byte4 | byte3 | byte2 | byte1; return byte4 | byte3 | byte2 | byte1;
} }

177
src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Argb32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Argb32>
{
/// <inheritdoc />
internal override void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<Argb32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Argb32> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Argb32> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Argb32> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Argb32> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Argb32> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Argb32> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Argb32> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Argb32> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Argb32> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Argb32.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Argb32> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromArgb32(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Argb32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Argb32>
{
/// <inheritdoc />
internal override void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<Argb32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Argb32> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Bgr24
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Bgr24>
{
/// <inheritdoc />
internal override void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<Bgr24> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Bgr24> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Bgr24> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Bgr24> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Bgr24> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Bgr24> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Bgr24> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Bgr24.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Bgr24> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgr24(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Bgr24
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Bgr24>
{
/// <inheritdoc />
internal override void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<Bgr24> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Bgr24> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Bgra32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Bgra32>
{
/// <inheritdoc />
internal override void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<Bgra32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Bgra32> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Bgra32> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Bgra32> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Bgra32> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Bgra32> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Bgra32> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Bgra32.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Bgra32> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromBgra32(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Bgra32
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Bgra32>
{
/// <inheritdoc />
internal override void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<Bgra32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Bgra32> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Gray16
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Gray16>
{
/// <inheritdoc />
internal override void PackFromGray16(ReadOnlySpan<Gray16> source, Span<Gray16> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Gray16> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Gray16> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Gray16> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Gray16> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Gray16> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Gray16> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Gray16> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Gray16> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Gray16> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Gray16.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Gray16> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray16(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Gray16
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Gray16>
{
/// <inheritdoc />
internal override void PackFromGray16(ReadOnlySpan<Gray16> source, Span<Gray16> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Gray16> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Gray8
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Gray8>
{
/// <inheritdoc />
internal override void PackFromGray8(ReadOnlySpan<Gray8> source, Span<Gray8> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Gray8> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Gray8> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Gray8> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Gray8> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Gray8> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Gray8> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Gray8> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Gray8> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Gray8> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Gray8.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Gray8> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Gray8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray8 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromGray8(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Gray8
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Gray8>
{
/// <inheritdoc />
internal override void PackFromGray8(ReadOnlySpan<Gray8> source, Span<Gray8> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Gray8> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

621
src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs

@ -10,296 +10,357 @@ namespace SixLabors.ImageSharp.PixelFormats
public partial class PixelOperations<TPixel> public partial class PixelOperations<TPixel>
{ {
/// <summary>
/// <summary> /// Converts 'count' elements in 'source` span of <see cref="Argb32"/> data to a span of <typeparamref name="TPixel"/>-s.
/// Converts 'count' elements in 'source` span of <see cref="Rgba64"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary> /// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba64"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Argb32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgba64(ReadOnlySpan<Rgba64> source, Span<TPixel> destPixels, int count) internal virtual void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgba64>.Black;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel dp = ref Unsafe.Add(ref destRef, i); ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i);
temp = Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgba64(temp);
dp.PackFromArgb32(sp);
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromRgba64(ReadOnlySpan{Rgba64}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromArgb32(ReadOnlySpan{Argb32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba64"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Argb32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgba64Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromArgb32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromRgba64(MemoryMarshal.Cast<byte, Rgba64>(sourceBytes), destPixels, count); this.PackFromArgb32(MemoryMarshal.Cast<byte, Argb32>(sourceBytes), destPixels, count);
} }
/// <summary> /// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgba64"/>-s. /// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Argb32"/>-s.
/// Bulk version of <see cref="IPixel.ToRgba64(ref Rgba64)"/>.
/// </summary> /// </summary>
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgba64"/> data.</param> /// <param name="destPixels">The destination span of <see cref="Argb32"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgba64(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba64> dest, int count) internal virtual void ToArgb32(ReadOnlySpan<TPixel> sourcePixels, Span<Argb32> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(dest); ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToRgba64(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToRgba64(ReadOnlySpan{TPixel}, Span{Rgba64}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToArgb32(ReadOnlySpan{TPixel}, Span{Argb32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba64"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Argb32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba64Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToArgb32Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{ {
this.ToRgba64(sourceColors, MemoryMarshal.Cast<byte, Rgba64>(destBytes), count); this.ToArgb32(sourcePixels, MemoryMarshal.Cast<byte, Argb32>(destBytes), count);
} }
/// <summary> /// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgb48"/> data to a span of <typeparamref name="TPixel"/>-s. /// Converts 'count' elements in 'source` span of <see cref="Bgr24"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary> /// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb48"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgr24"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgb48(ReadOnlySpan<Rgb48> source, Span<TPixel> destPixels, int count) internal virtual void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source); ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgb48>.Black;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel dp = ref Unsafe.Add(ref destRef, i); ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i);
temp = Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgb48(temp);
dp.PackFromBgr24(sp);
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromRgb48(ReadOnlySpan{Rgb48}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromBgr24(ReadOnlySpan{Bgr24}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb48"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgr24"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgb48Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromBgr24Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromRgb48(MemoryMarshal.Cast<byte, Rgb48>(sourceBytes), destPixels, count); this.PackFromBgr24(MemoryMarshal.Cast<byte, Bgr24>(sourceBytes), destPixels, count);
} }
/// <summary> /// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgb48"/>-s. /// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgr24"/>-s.
/// Bulk version of <see cref="IPixel.ToRgb48(ref Rgb48)"/>.
/// </summary> /// </summary>
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgb48"/> data.</param> /// <param name="destPixels">The destination span of <see cref="Bgr24"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgb48(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb48> dest, int count) internal virtual void ToBgr24(ReadOnlySpan<TPixel> sourcePixels, Span<Bgr24> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(dest); ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToRgb48(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToRgb48(ReadOnlySpan{TPixel}, Span{Rgb48}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToBgr24(ReadOnlySpan{TPixel}, Span{Bgr24}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb48"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Bgr24"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgb48Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToBgr24Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{ {
this.ToRgb48(sourceColors, MemoryMarshal.Cast<byte, Rgb48>(destBytes), count); this.ToBgr24(sourcePixels, MemoryMarshal.Cast<byte, Bgr24>(destBytes), count);
} }
/// <summary> /// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgba32"/> data to a span of <typeparamref name="TPixel"/>-s. /// Converts 'count' elements in 'source` span of <see cref="Bgra32"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary> /// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba32"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgra32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<TPixel> destPixels, int count) internal virtual void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source); ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgba32>.Black;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel dp = ref Unsafe.Add(ref destRef, i); ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i);
temp = Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgba32(temp);
dp.PackFromBgra32(sp);
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromRgba32(ReadOnlySpan{Rgba32}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromBgra32(ReadOnlySpan{Bgra32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba32"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgra32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgba32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromBgra32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromRgba32(MemoryMarshal.Cast<byte, Rgba32>(sourceBytes), destPixels, count); this.PackFromBgra32(MemoryMarshal.Cast<byte, Bgra32>(sourceBytes), destPixels, count);
} }
/// <summary> /// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgba32"/>-s. /// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgra32"/>-s.
/// Bulk version of <see cref="IPixel.ToRgba32(ref Rgba32)"/>.
/// </summary> /// </summary>
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgba32"/> data.</param> /// <param name="destPixels">The destination span of <see cref="Bgra32"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgba32(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba32> dest, int count) internal virtual void ToBgra32(ReadOnlySpan<TPixel> sourcePixels, Span<Bgra32> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(dest); ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToRgba32(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToRgba32(ReadOnlySpan{TPixel}, Span{Rgba32}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToBgra32(ReadOnlySpan{TPixel}, Span{Bgra32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba32"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Bgra32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba32Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToBgra32Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{ {
this.ToRgba32(sourceColors, MemoryMarshal.Cast<byte, Rgba32>(destBytes), count); this.ToBgra32(sourcePixels, MemoryMarshal.Cast<byte, Bgra32>(destBytes), count);
} }
/// <summary> /// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Bgra32"/> data to a span of <typeparamref name="TPixel"/>-s. /// Converts 'count' elements in 'source` span of <see cref="Gray8"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary> /// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgra32"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Gray8"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<TPixel> destPixels, int count) internal virtual void PackFromGray8(ReadOnlySpan<Gray8> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); ref Gray8 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! for (int i = 0; i < count; i++)
var temp = NamedColors<Bgra32>.Black; {
ref Gray8 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromGray8(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromGray8(ReadOnlySpan{Gray8}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Gray8"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromGray8Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromGray8(MemoryMarshal.Cast<byte, Gray8>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Gray8"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Gray8"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToGray8(ReadOnlySpan<TPixel> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel dp = ref Unsafe.Add(ref destRef, i); ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
temp = Unsafe.Add(ref sourceRef, i); ref Gray8 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromBgra32(temp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromBgra32(ReadOnlySpan{Bgra32}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="ToGray8(ReadOnlySpan{TPixel}, Span{Gray8}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgra32"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Gray8"/> layout.
/// </summary>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToGray8Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToGray8(sourcePixels, MemoryMarshal.Cast<byte, Gray8>(destBytes), count);
}
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Gray16"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Gray16"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromGray16(ReadOnlySpan<Gray16> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Gray16 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Gray16 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromGray16(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromGray16(ReadOnlySpan{Gray16}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Gray16"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromBgra32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromGray16Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromBgra32(MemoryMarshal.Cast<byte, Bgra32>(sourceBytes), destPixels, count); this.PackFromGray16(MemoryMarshal.Cast<byte, Gray16>(sourceBytes), destPixels, count);
} }
/// <summary> /// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgra32"/>-s. /// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Gray16"/>-s.
/// Bulk version of <see cref="IPixel.ToBgra32(ref Bgra32)"/>.
/// </summary> /// </summary>
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Bgra32"/> data.</param> /// <param name="destPixels">The destination span of <see cref="Gray16"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToBgra32(ReadOnlySpan<TPixel> sourcePixels, Span<Bgra32> dest, int count) internal virtual void ToGray16(ReadOnlySpan<TPixel> sourcePixels, Span<Gray16> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(dest); ref Gray16 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); ref Gray16 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToBgra32(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToBgra32(ReadOnlySpan{TPixel}, Span{Bgra32}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToGray16(ReadOnlySpan{TPixel}, Span{Gray16}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgra32"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Gray16"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgra32Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToGray16Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{ {
this.ToBgra32(sourceColors, MemoryMarshal.Cast<byte, Bgra32>(destBytes), count); this.ToGray16(sourcePixels, MemoryMarshal.Cast<byte, Gray16>(destBytes), count);
} }
/// <summary> /// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgb24"/> data to a span of <typeparamref name="TPixel"/>-s. /// Converts 'count' elements in 'source` span of <see cref="Rgb24"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary> /// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb24"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb24"/> data.</param>
@ -307,23 +368,21 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<TPixel> destPixels, int count) internal virtual void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgba32>.Black;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel dp = ref Unsafe.Add(ref destRef, i); ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i);
temp.Rgb = Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgba32(temp);
dp.PackFromRgb24(sp);
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromRgb24(ReadOnlySpan{Rgb24}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromRgb24(ReadOnlySpan{Rgb24}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb24"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb24"/> layout.
/// </summary> /// </summary>
@ -335,186 +394,250 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
this.PackFromRgb24(MemoryMarshal.Cast<byte, Rgb24>(sourceBytes), destPixels, count); this.PackFromRgb24(MemoryMarshal.Cast<byte, Rgb24>(sourceBytes), destPixels, count);
} }
/// <summary> /// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgb24"/>-s. /// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgb24"/>-s.
/// Bulk version of <see cref="IPixel.ToRgb24(ref Rgb24)"/>.
/// </summary> /// </summary>
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Rgb24"/> data.</param> /// <param name="destPixels">The destination span of <see cref="Rgb24"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgb24(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb24> dest, int count) internal virtual void ToRgb24(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb24> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(dest); ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToRgb24(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToRgb24(ReadOnlySpan{TPixel}, Span{Rgb24}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToRgb24(ReadOnlySpan{TPixel}, Span{Rgb24}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb24"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb24"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgb24Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToRgb24Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{ {
this.ToRgb24(sourceColors, MemoryMarshal.Cast<byte, Rgb24>(destBytes), count); this.ToRgb24(sourcePixels, MemoryMarshal.Cast<byte, Rgb24>(destBytes), count);
} }
/// <summary> /// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Bgr24"/> data to a span of <typeparamref name="TPixel"/>-s. /// Converts 'count' elements in 'source` span of <see cref="Rgba32"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary> /// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Bgr24"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba32"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<TPixel> destPixels, int count) internal virtual void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Rgba32>.Black;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel dp = ref Unsafe.Add(ref destRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i);
temp.Bgr = Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgba32(temp);
dp.PackFromRgba32(sp);
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromBgr24(ReadOnlySpan{Bgr24}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromRgba32(ReadOnlySpan{Rgba32}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Bgr24"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromBgr24Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromRgba32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromBgr24(MemoryMarshal.Cast<byte, Bgr24>(sourceBytes), destPixels, count); this.PackFromRgba32(MemoryMarshal.Cast<byte, Rgba32>(sourceBytes), destPixels, count);
} }
/// <summary> /// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Bgr24"/>-s. /// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgba32"/>-s.
/// Bulk version of <see cref="IPixel.ToBgr24(ref Bgr24)"/>.
/// </summary> /// </summary>
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Bgr24"/> data.</param> /// <param name="destPixels">The destination span of <see cref="Rgba32"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToBgr24(ReadOnlySpan<TPixel> sourcePixels, Span<Bgr24> dest, int count) internal virtual void ToRgba32(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba32> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(dest); ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToBgr24(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToBgr24(ReadOnlySpan{TPixel}, Span{Bgr24}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToRgba32(ReadOnlySpan{TPixel}, Span{Rgba32}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Bgr24"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba32"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToBgr24Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToRgba32Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{ {
this.ToBgr24(sourceColors, MemoryMarshal.Cast<byte, Bgr24>(destBytes), count); this.ToRgba32(sourcePixels, MemoryMarshal.Cast<byte, Rgba32>(destBytes), count);
} }
/// <summary> /// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Argb32"/> data to a span of <typeparamref name="TPixel"/>-s. /// Converts 'count' elements in 'source` span of <see cref="Rgb48"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary> /// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Argb32"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgb48"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<TPixel> destPixels, int count) internal virtual void PackFromRgb48(ReadOnlySpan<Rgb48> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<Argb32>.Black;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel dp = ref Unsafe.Add(ref destRef, i); ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i);
temp = Unsafe.Add(ref sourceRef, i); ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromArgb32(temp);
dp.PackFromRgb48(sp);
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFromArgb32(ReadOnlySpan{Argb32}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFromRgb48(ReadOnlySpan{Rgb48}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Argb32"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgb48"/> layout.
/// </summary> /// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param> /// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param> /// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromArgb32Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count) internal void PackFromRgb48Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{ {
this.PackFromArgb32(MemoryMarshal.Cast<byte, Argb32>(sourceBytes), destPixels, count); this.PackFromRgb48(MemoryMarshal.Cast<byte, Rgb48>(sourceBytes), destPixels, count);
} }
/// <summary> /// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Argb32"/>-s. /// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgb48"/>-s.
/// Bulk version of <see cref="IPixel.ToArgb32(ref Argb32)"/>.
/// </summary> /// </summary>
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="Argb32"/> data.</param> /// <param name="destPixels">The destination span of <see cref="Rgb48"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void ToArgb32(ReadOnlySpan<TPixel> sourcePixels, Span<Argb32> dest, int count) internal virtual void ToRgb48(ReadOnlySpan<TPixel> sourcePixels, Span<Rgb48> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(dest); ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i);
sp.ToArgb32(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="ToArgb32(ReadOnlySpan{TPixel}, Span{Argb32}, int)"/> that expects a byte span as destination. /// A helper for <see cref="ToRgb48(ReadOnlySpan{TPixel}, Span{Rgb48}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Argb32"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="Rgb48"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToArgb32Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count) internal void ToRgb48Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgb48(sourcePixels, MemoryMarshal.Cast<byte, Rgb48>(destBytes), count);
}
/// <summary>
/// Converts 'count' elements in 'source` span of <see cref="Rgba64"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="Rgba64"/> data.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFromRgba64(ReadOnlySpan<Rgba64> source, Span<TPixel> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromRgba64(sp);
}
}
/// <summary>
/// A helper for <see cref="PackFromRgba64(ReadOnlySpan{Rgba64}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="Rgba64"/> layout.
/// </summary>
/// <param name="sourceBytes">The <see cref="ReadOnlySpan{T}"/> to the source bytes.</param>
/// <param name="destPixels">The <see cref="Span{T}"/> to the destination pixels.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void PackFromRgba64Bytes(ReadOnlySpan<byte> sourceBytes, Span<TPixel> destPixels, int count)
{
this.PackFromRgba64(MemoryMarshal.Cast<byte, Rgba64>(sourceBytes), destPixels, count);
}
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="Rgba64"/>-s.
/// </summary>
/// <param name="sourcePixels">The span of source pixels</param>
/// <param name="destPixels">The destination span of <see cref="Rgba64"/> data.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void ToRgba64(ReadOnlySpan<TPixel> sourcePixels, Span<Rgba64> destPixels, int count)
{ {
this.ToArgb32(sourceColors, MemoryMarshal.Cast<byte, Argb32>(destBytes), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
} }
}
/// <summary>
/// A helper for <see cref="ToRgba64(ReadOnlySpan{TPixel}, Span{Rgba64}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="Rgba64"/> layout.
/// </summary>
/// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void ToRgba64Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{
this.ToRgba64(sourcePixels, MemoryMarshal.Cast<byte, Rgba64>(destBytes), count);
}
}
} }

92
src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt

@ -11,11 +11,11 @@
<#@ output extension=".cs" #> <#@ output extension=".cs" #>
<# <#
void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) void GeneratePackFromMethods(string pixelType)
{ {
#> #>
/// <summary> /// <summary>
/// Converts 'count' elements in 'source` span of <see cref="<#=pixelType#>"/> data to a span of <typeparamref name="TPixel"/>-s. /// Converts 'count' elements in 'source` span of <see cref="<#=pixelType#>"/> data to a span of <typeparamref name="TPixel"/>-s.
/// </summary> /// </summary>
/// <param name="source">The source <see cref="Span{T}"/> of <see cref="<#=pixelType#>"/> data.</param> /// <param name="source">The source <see cref="Span{T}"/> of <see cref="<#=pixelType#>"/> data.</param>
@ -23,23 +23,21 @@
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<TPixel> destPixels, int count) internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<TPixel> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source);
ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destPixels);
// For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque!
var temp = NamedColors<<#=tempPixelType#>>.Black;
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel dp = ref Unsafe.Add(ref destRef, i); ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i);
<#=assignToTempCode#> ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i);
dp.PackFrom<#=tempPixelType#>(temp);
dp.PackFrom<#=pixelType#>(sp);
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="PackFrom<#=pixelType#>(ReadOnlySpan{<#=pixelType#>}, Span{TPixel}, int)"/> that expects a byte span. /// A helper for <see cref="PackFrom<#=pixelType#>(ReadOnlySpan{<#=pixelType#>}, Span{TPixel}, int)"/> that expects a byte span.
/// The layout of the data in 'sourceBytes' must be compatible with <see cref="<#=pixelType#>"/> layout. /// The layout of the data in 'sourceBytes' must be compatible with <see cref="<#=pixelType#>"/> layout.
/// </summary> /// </summary>
@ -51,48 +49,48 @@
{ {
this.PackFrom<#=pixelType#>(MemoryMarshal.Cast<byte, <#=pixelType#>>(sourceBytes), destPixels, count); this.PackFrom<#=pixelType#>(MemoryMarshal.Cast<byte, <#=pixelType#>>(sourceBytes), destPixels, count);
} }
<#
<#
} }
void GenerateToDestFormatMethods(string pixelType) void GenerateToDestFormatMethods(string pixelType)
{ {
#> #>
/// <summary>
/// <summary>
/// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="<#=pixelType#>"/>-s. /// Converts 'count' pixels in 'sourcePixels` span to a span of <see cref="<#=pixelType#>"/>-s.
/// Bulk version of <see cref="IPixel.To<#=pixelType#>(ref <#=pixelType#>)"/>.
/// </summary> /// </summary>
/// <param name="sourcePixels">The span of source pixels</param> /// <param name="sourcePixels">The span of source pixels</param>
/// <param name="dest">The destination span of <see cref="<#=pixelType#>"/> data.</param> /// <param name="destPixels">The destination span of <see cref="<#=pixelType#>"/> data.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
internal virtual void To<#=pixelType#>(ReadOnlySpan<TPixel> sourcePixels, Span<<#=pixelType#>> dest, int count) internal virtual void To<#=pixelType#>(ReadOnlySpan<TPixel> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(dest); ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i);
sp.To<#=pixelType#>(ref dp);
dp.PackFromScaledVector4(sp.ToScaledVector4());
} }
} }
/// <summary> /// <summary>
/// A helper for <see cref="To<#=pixelType#>(ReadOnlySpan{TPixel}, Span{<#=pixelType#>}, int)"/> that expects a byte span as destination. /// A helper for <see cref="To<#=pixelType#>(ReadOnlySpan{TPixel}, Span{<#=pixelType#>}, int)"/> that expects a byte span as destination.
/// The layout of the data in 'destBytes' must be compatible with <see cref="<#=pixelType#>"/> layout. /// The layout of the data in 'destBytes' must be compatible with <see cref="<#=pixelType#>"/> layout.
/// </summary> /// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param> /// <param name="sourcePixels">The <see cref="Span{T}"/> to the source pixels.</param>
/// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param> /// <param name="destBytes">The <see cref="Span{T}"/> to the destination bytes.</param>
/// <param name="count">The number of pixels to convert.</param> /// <param name="count">The number of pixels to convert.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
internal void To<#=pixelType#>Bytes(ReadOnlySpan<TPixel> sourceColors, Span<byte> destBytes, int count) internal void To<#=pixelType#>Bytes(ReadOnlySpan<TPixel> sourcePixels, Span<byte> destBytes, int count)
{ {
this.To<#=pixelType#>(sourceColors, MemoryMarshal.Cast<byte, <#=pixelType#>>(destBytes), count); this.To<#=pixelType#>(sourcePixels, MemoryMarshal.Cast<byte, <#=pixelType#>>(destBytes), count);
} }
<# <#
} }
#> #>
@ -107,30 +105,34 @@ namespace SixLabors.ImageSharp.PixelFormats
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
public partial class PixelOperations<TPixel> public partial class PixelOperations<TPixel>
{ {<#
<#
GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);");
GenerateToDestFormatMethods("Rgba64");
GeneratePackFromMethods("Rgb48", "Rgb48", "temp = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Argb32");
GenerateToDestFormatMethods("Rgb48"); GenerateToDestFormatMethods("Argb32");
GeneratePackFromMethods("Rgba32", "Rgba32", "temp = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Bgr24");
GenerateToDestFormatMethods("Rgba32"); GenerateToDestFormatMethods("Bgr24");
GeneratePackFromMethods("Bgra32", "Bgra32", "temp = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Bgra32");
GenerateToDestFormatMethods("Bgra32"); GenerateToDestFormatMethods("Bgra32");
GeneratePackFromMethods("Rgb24", "Rgba32", "temp.Rgb = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Gray8");
GenerateToDestFormatMethods("Gray8");
GeneratePackFromMethods("Gray16");
GenerateToDestFormatMethods("Gray16");
GeneratePackFromMethods("Rgb24");
GenerateToDestFormatMethods("Rgb24"); GenerateToDestFormatMethods("Rgb24");
GeneratePackFromMethods("Bgr24", "Rgba32", "temp.Bgr = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Rgba32");
GenerateToDestFormatMethods("Bgr24"); GenerateToDestFormatMethods("Rgba32");
GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Rgb48");
GenerateToDestFormatMethods("Argb32"); GenerateToDestFormatMethods("Rgb48");
#>
} GeneratePackFromMethods("Rgba64");
GenerateToDestFormatMethods("Rgba64");
#> }
} }

177
src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgb24
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgb24>
{
/// <inheritdoc />
internal override void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<Rgb24> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgb24> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgb24> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgb24> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgb24> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgb24> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Rgb24.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Rgb24> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb24(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgb24
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgb24>
{
/// <inheritdoc />
internal override void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<Rgb24> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgb24> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgb48
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgb48>
{
/// <inheritdoc />
internal override void PackFromRgb48(ReadOnlySpan<Rgb48> source, Span<Rgb48> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgb48> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgb48> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgb48> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgb48> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgb48> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Rgb48.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Rgb48> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgb48(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgb48
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgb48>
{
/// <inheritdoc />
internal override void PackFromRgb48(ReadOnlySpan<Rgb48> source, Span<Rgb48> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgb48> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgba64");
#>
}
}
}

124
src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.cs

@ -13,134 +13,162 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </content> /// </content>
public partial struct Rgba32 public partial struct Rgba32
{ {
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
internal partial class PixelOperations internal partial class PixelOperations
{ {
/// <inheritdoc />
internal override void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFromRgb24(ReadOnlySpan<Rgb24> source, Span<Rgba32> destPixels, int count) internal override void ToArgb32(ReadOnlySpan<Rgba32> sourcePixels, Span<Argb32> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
Unsafe.As<Rgba32, Rgb24>(ref dp) = sp; dp.A = 255;
dp.PackFromRgba32(sp);
} }
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb24> dest, int count) internal override void ToBgr24(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgr24> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(dest); ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp = Unsafe.As<Rgba32, Rgb24>(ref sp);
dp.PackFromRgba32(sp);
} }
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFromBgr24(ReadOnlySpan<Bgr24> source, Span<Rgba32> destPixels, int count) internal override void ToBgra32(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgra32> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.Bgr = sp; dp.A = 255;
dp.PackFromRgba32(sp);
} }
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgr24> dest, int count) internal override void ToGray8(ReadOnlySpan<Rgba32> sourcePixels, Span<Gray8> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(dest); ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.Bgr;
dp.PackFromRgba32(sp);
} }
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFromBgra32(ReadOnlySpan<Bgra32> source, Span<Rgba32> destPixels, int count) internal override void ToGray16(ReadOnlySpan<Rgba32> sourcePixels, Span<Gray16> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToRgba32();
dp.PackFromRgba32(sp);
} }
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgba32> sourcePixels, Span<Bgra32> dest, int count) internal override void ToRgb24(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb24> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(dest); ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToBgra32();
dp.PackFromRgba32(sp);
} }
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFromArgb32(ReadOnlySpan<Argb32> source, Span<Rgba32> destPixels, int count) internal override void ToRgb48(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgb48> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels); ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToRgba32();
dp.PackFromRgba32(sp);
} }
} }
/// <inheritdoc /> /// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgba32> sourcePixels, Span<Argb32> dest, int count) internal override void ToRgba64(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba64> destPixels, int count)
{ {
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(dest); ref Rgba64 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i); ref Rgba64 dp = ref Unsafe.Add(ref destRef, i);
dp = sp.ToArgb32();
dp.PackFromRgba32(sp);
} }
} }

70
src/ImageSharp/PixelFormats/Generated/Rgba32.PixelOperations.Generated.tt

@ -9,45 +9,24 @@
<#@ import namespace="System.Collections.Generic" #> <#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #> <#@ output extension=".cs" #>
<# <#
void GeneratePackFromMethod(string pixelType, string converterCode) void GenerateConvertToMethod(string pixelType)
{ {
#> #>
/// <inheritdoc /> /// <inheritdoc />
internal override void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span<Rgba32> destPixels, int count) internal override void To<#=pixelType#>(ReadOnlySpan<Rgba32> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{ {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
<#=converterCode#>
}
}
<#
}
void GenerateConvertToMethod(string pixelType, string converterCode)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Rgba32> sourcePixels, Span<<#=pixelType#>> dest, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(dest); ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++) for (int i = 0; i < count; i++)
{ {
ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i); ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
<#=converterCode#>
dp.PackFromRgba32(sp);
} }
} }
<# <#
@ -68,20 +47,37 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </content> /// </content>
public partial struct Rgba32 public partial struct Rgba32
{ {
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
internal partial class PixelOperations internal partial class PixelOperations
{ {
<# /// <inheritdoc />
GeneratePackFromMethod("Rgb24", "Unsafe.As<Rgba32, Rgb24>(ref dp) = sp; dp.A = 255;"); internal override void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels, int count)
GenerateConvertToMethod("Rgb24", "dp = Unsafe.As<Rgba32, Rgb24>(ref sp);"); {
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
GeneratePackFromMethod("Bgr24", "dp.Bgr = sp; dp.A = 255;"); source.Slice(0, count).CopyTo(destPixels);
GenerateConvertToMethod("Bgr24", "dp = sp.Bgr;"); }
GeneratePackFromMethod("Bgra32", "dp = sp.ToRgba32();"); /// <inheritdoc />
GenerateConvertToMethod("Bgra32", "dp = sp.ToBgra32();"); internal override void ToRgba32(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
GeneratePackFromMethod("Argb32", "dp = sp.ToRgba32();"); sourcePixels.Slice(0, count).CopyTo(destPixels);
GenerateConvertToMethod("Argb32", "dp = sp.ToArgb32();"); }
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgb48");
GenerateConvertToMethod("Rgba64");
#> #>
} }

177
src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgba64
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgba64>
{
/// <inheritdoc />
internal override void PackFromRgba64(ReadOnlySpan<Rgba64> source, Span<Rgba64> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToArgb32(ReadOnlySpan<Rgba64> sourcePixels, Span<Argb32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Argb32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Argb32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToBgr24(ReadOnlySpan<Rgba64> sourcePixels, Span<Bgr24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgr24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgr24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToBgra32(ReadOnlySpan<Rgba64> sourcePixels, Span<Bgra32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Bgra32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Bgra32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToGray8(ReadOnlySpan<Rgba64> sourcePixels, Span<Gray8> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray8 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToGray16(ReadOnlySpan<Rgba64> sourcePixels, Span<Gray16> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Gray16 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToRgb24(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgb24> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb24 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb24 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba32> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgba32 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgba32 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
/// <inheritdoc />
internal override void ToRgb48(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgb48> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref Rgb48 destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref Rgb48 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
}
}
}

85
src/ImageSharp/PixelFormats/Generated/Rgba64.PixelOperations.Generated.tt

@ -0,0 +1,85 @@
<#
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
#>
<#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #>
<#
void GenerateConvertToMethod(string pixelType)
{
#>
/// <inheritdoc />
internal override void To<#=pixelType#>(ReadOnlySpan<Rgba64> sourcePixels, Span<<#=pixelType#>> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels);
ref <#=pixelType#> destRef = ref MemoryMarshal.GetReference(destPixels);
for (int i = 0; i < count; i++)
{
ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i);
ref <#=pixelType#> dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromRgba64(sp);
}
}
<#
}
#>
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
// <auto-generated />
namespace SixLabors.ImageSharp.PixelFormats
{
using System;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
/// <content>
/// Provides optimized overrides for bulk operations.
/// </content>
public partial struct Rgba64
{
/// <summary>
/// Provides optimized overrides for bulk operations.
/// </summary>
internal class PixelOperations : PixelOperations<Rgba64>
{
/// <inheritdoc />
internal override void PackFromRgba64(ReadOnlySpan<Rgba64> source, Span<Rgba64> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba64(ReadOnlySpan<Rgba64> sourcePixels, Span<Rgba64> destPixels, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), destPixels, nameof(destPixels), count);
sourcePixels.Slice(0, count).CopyTo(destPixels);
}
<#
GenerateConvertToMethod("Argb32");
GenerateConvertToMethod("Bgr24");
GenerateConvertToMethod("Bgra32");
GenerateConvertToMethod("Gray8");
GenerateConvertToMethod("Gray16");
GenerateConvertToMethod("Rgb24");
GenerateConvertToMethod("Rgba32");
GenerateConvertToMethod("Rgb48");
#>
}
}
}

177
src/ImageSharp/PixelFormats/Gray16.cs

@ -0,0 +1,177 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Packed pixel type containing a single 16 bit normalized gray values.
/// <para>
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public partial struct Gray16 : IPixel<Gray16>, IPackedVector<ushort>
{
private const float Max = ushort.MaxValue;
private const float Average = 1 / 3F;
/// <summary>
/// Initializes a new instance of the <see cref="Gray16"/> struct.
/// </summary>
/// <param name="luminance">The luminance component</param>
public Gray16(ushort luminance) => this.PackedValue = luminance;
/// <inheritdoc />
public ushort PackedValue { get; set; }
/// <summary>
/// Compares two <see cref="Gray16"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Gray16"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Gray16"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Gray16 left, Gray16 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Gray16"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Gray16"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Gray16"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Gray16 left, Gray16 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Gray16> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max * Average;
this.PackedValue = (ushort)MathF.Round(vector.X + vector.Y + vector.Z);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
float scaled = this.PackedValue / Max;
return new Vector4(scaled, scaled, scaled, 1F);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackedValue = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackedValue = source.PackedValue;
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source)
{
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
ImageMaths.UpscaleFrom8BitTo16Bit(source.R),
ImageMaths.UpscaleFrom8BitTo16Bit(source.G),
ImageMaths.UpscaleFrom8BitTo16Bit(source.B));
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32()
{
byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(this.PackedValue);
return new Rgba32(rgb, rgb, rgb, byte.MaxValue);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this.PackedValue = ImageMaths.Get16BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc />
public override bool Equals(object obj) => obj is Gray16 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Gray16 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString() => $"Gray16({this.PackedValue})";
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector)
{
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max;
this.PackedValue = ImageMaths.Get16BitBT709Luminance(
(ushort)MathF.Round(vector.X),
(ushort)MathF.Round(vector.Y),
(ushort)MathF.Round(vector.Z));
}
}
}

152
src/ImageSharp/PixelFormats/Gray8.cs

@ -0,0 +1,152 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
using System.Numerics;
using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Packed pixel type containing a single 8 bit normalized gray values.
/// <para>
/// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form.
/// </para>
/// </summary>
public partial struct Gray8 : IPixel<Gray8>, IPackedVector<byte>
{
private static readonly Vector4 MaxBytes = new Vector4(255F);
private static readonly Vector4 Half = new Vector4(0.5F);
private const float Average = 1 / 3F;
/// <summary>
/// Initializes a new instance of the <see cref="Gray8"/> struct.
/// </summary>
/// <param name="luminance">The luminance component.</param>
public Gray8(byte luminance) => this.PackedValue = luminance;
/// <inheritdoc />
public byte PackedValue { get; set; }
/// <summary>
/// Compares two <see cref="Gray8"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Gray8"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Gray8"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Gray8 left, Gray8 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Gray8"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Gray8"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Gray8"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Gray8 left, Gray8 right) => !left.Equals(right);
/// <inheritdoc />
public PixelOperations<Gray8> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() => this.ToVector4();
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector)
{
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes) * Average;
this.PackedValue = (byte)(vector.X + vector.Y + vector.Z);
}
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
float rgb = this.PackedValue / 255F;
return new Vector4(rgb, rgb, rgb, 1F);
}
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgr24(Bgr24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray8(Gray8 source) => this.PackedValue = source.PackedValue;
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackedValue = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb24(Rgb24 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) => this.PackedValue = ImageMaths.Get8BitBT709Luminance(source.R, source.G, source.B);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public Rgba32 ToRgba32() => new Rgba32(this.PackedValue, this.PackedValue, this.PackedValue, byte.MaxValue);
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
=> this.PackedValue = ImageMaths.Get8BitBT709Luminance(
ImageMaths.DownScaleFrom16BitTo8Bit(source.R),
ImageMaths.DownScaleFrom16BitTo8Bit(source.G),
ImageMaths.DownScaleFrom16BitTo8Bit(source.B));
/// <inheritdoc/>
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source)
=> this.PackedValue = ImageMaths.Get8BitBT709Luminance(
ImageMaths.DownScaleFrom16BitTo8Bit(source.R),
ImageMaths.DownScaleFrom16BitTo8Bit(source.G),
ImageMaths.DownScaleFrom16BitTo8Bit(source.B));
/// <inheritdoc />
public override bool Equals(object obj) => obj is Gray8 other && this.Equals(other);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Gray8 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
public override string ToString() => $"Gray8({this.PackedValue}";
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(InliningOptions.ShortMethod)]
internal void ConvertFromRgbaScaledVector4(Vector4 vector)
{
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
this.PackedValue = ImageMaths.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z);
}
}
}

202
src/ImageSharp/PixelFormats/HalfSingle.cs

@ -1,6 +1,7 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
@ -14,24 +15,11 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public struct HalfSingle : IPixel<HalfSingle>, IPackedVector<ushort> public struct HalfSingle : IPixel<HalfSingle>, IPackedVector<ushort>
{ {
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HalfSingle"/> struct. /// Initializes a new instance of the <see cref="HalfSingle"/> struct.
/// </summary> /// </summary>
/// <param name="single">The single component.</param> /// <param name="single">The single component.</param>
public HalfSingle(float single) public HalfSingle(float single) => this.PackedValue = HalfTypeHelper.Pack(single);
{
this.PackedValue = HalfTypeHelper.Pack(single);
}
/// <inheritdoc/> /// <inheritdoc/>
public ushort PackedValue { get; set; } public ushort PackedValue { get; set; }
@ -39,206 +27,114 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Compares two <see cref="HalfSingle"/> objects for equality. /// Compares two <see cref="HalfSingle"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="HalfSingle"/> on the left side of the operand.</param>
/// The <see cref="HalfSingle"/> on the left side of the operand. /// <param name="right">The <see cref="HalfSingle"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="HalfSingle"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(HalfSingle left, HalfSingle right) public static bool operator ==(HalfSingle left, HalfSingle right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="HalfSingle"/> objects for equality. /// Compares two <see cref="HalfSingle"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="HalfSingle"/> on the left side of the operand.</param>
/// The <see cref="HalfSingle"/> on the left side of the operand. /// <param name="right">The <see cref="HalfSingle"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="HalfSingle"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(HalfSingle left, HalfSingle right) public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<HalfSingle> CreatePixelOperations() => new PixelOperations<HalfSingle>(); public PixelOperations<HalfSingle> CreatePixelOperations() => new PixelOperations<HalfSingle>();
/// <summary>
/// Expands the packed representation into a <see cref="float"/>.
/// </summary>
/// <returns>The <see cref="float"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public float ToSingle()
{
return HalfTypeHelper.Unpack(this.PackedValue);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector)
{ {
float scaled = vector.X; float scaled = vector.X;
scaled *= 2F; scaled *= 2F;
scaled -= 1F; scaled--;
this.PackedValue = HalfTypeHelper.Pack(scaled); this.PackedValue = HalfTypeHelper.Pack(scaled);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4()
{ {
float single = this.ToSingle() + 1F; float single = this.ToSingle() + 1F;
single /= 2F; single /= 2F;
return new Vector4(single, 0, 0, 1); return new Vector4(single, 0, 0, 1F);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X);
{
this.PackedValue = HalfTypeHelper.Pack(vector.X);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4() => new Vector4(this.ToSingle(), 0, 0, 1F);
{
return new Vector4(this.ToSingle(), 0, 0, 1);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// Expands the packed representation into a <see cref="float"/>.
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// </summary>
/// <returns>The <see cref="float"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public float ToSingle() => HalfTypeHelper.Unpack(this.PackedValue);
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is HalfSingle other && this.Equals(other);
{
return obj is HalfSingle other && this.Equals(other);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(HalfSingle other) public bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue);
{
return this.PackedValue == other.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString() => FormattableString.Invariant($"HalfSingle({this.ToSingle():#0.##})");
{
return this.ToSingle().ToString();
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode(); public override int GetHashCode() => this.PackedValue.GetHashCode();
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
} }
} }

12
src/ImageSharp/PixelFormats/HalfTypeHelper.cs

@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Helper methods for packing and unpacking floating point values /// Helper methods for packing and unpacking floating point values
/// </summary> /// </summary>
internal class HalfTypeHelper internal static class HalfTypeHelper
{ {
/// <summary> /// <summary>
/// Packs a <see cref="float"/> into an <see cref="ushort"/> /// Packs a <see cref="float"/> into an <see cref="ushort"/>
@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats
return (ushort)s; return (ushort)s;
} }
m = m | 0x00800000; m |= 0x00800000;
int t = 14 - e; int t = 14 - e;
int a = (1 << (t - 1)) - 1; int a = (1 << (t - 1)) - 1;
@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.PixelFormats
if ((m & 0x00800000) != 0) if ((m & 0x00800000) != 0)
{ {
m = 0; m = 0;
e += 1; e++;
} }
if (e > 30) if (e > 30)
@ -97,11 +97,11 @@ namespace SixLabors.ImageSharp.PixelFormats
while ((mantissa & 1024) == 0) while ((mantissa & 1024) == 0)
{ {
exponent--; exponent--;
mantissa = mantissa << 1; mantissa <<= 1;
} }
mantissa &= 0xfffffbff; mantissa &= 0xfffffbff;
result = ((uint)((((uint)value & 0x8000) << 16) | ((exponent + 127) << 23))) | (mantissa << 13); result = (((uint)value & 0x8000) << 16) | ((exponent + 127) << 23) | (mantissa << 13);
} }
else else
{ {
@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
else else
{ {
result = ((((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23)) | (mantissa << 13); result = (((uint)value & 0x8000) << 16) | ((((((uint)value >> 10) & 0x1f) - 15) + 127) << 23) | (mantissa << 13);
} }
var uif = new Uif { U = result }; var uif = new Uif { U = result };

216
src/ImageSharp/PixelFormats/HalfVector2.cs

@ -15,34 +15,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public struct HalfVector2 : IPixel<HalfVector2>, IPackedVector<uint> public struct HalfVector2 : IPixel<HalfVector2>, IPackedVector<uint>
{ {
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HalfVector2"/> struct. /// Initializes a new instance of the <see cref="HalfVector2"/> struct.
/// </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>
public HalfVector2(float x, float y) public HalfVector2(float x, float y) => this.PackedValue = Pack(x, y);
{
this.PackedValue = Pack(x, y);
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HalfVector2"/> struct. /// Initializes a new instance of the <see cref="HalfVector2"/> struct.
/// </summary> /// </summary>
/// <param name="vector">A vector containing the initial values for the components.</param> /// <param name="vector">A vector containing the initial values for the components.</param>
public HalfVector2(Vector2 vector) public HalfVector2(Vector2 vector) => this.PackedValue = Pack(vector.X, vector.Y);
{
this.PackedValue = Pack(vector.X, vector.Y);
}
/// <inheritdoc/> /// <inheritdoc/>
public uint PackedValue { get; set; } public uint PackedValue { get; set; }
@ -50,57 +34,30 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality. /// Compares two <see cref="HalfVector2"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="HalfVector2"/> on the left side of the operand.</param>
/// The <see cref="HalfVector2"/> on the left side of the operand. /// <param name="right">The <see cref="HalfVector2"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="HalfVector2"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(HalfVector2 left, HalfVector2 right) public static bool operator ==(HalfVector2 left, HalfVector2 right) => left.Equals(right);
{
return left.Equals(right);
}
/// <summary> /// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality. /// Compares two <see cref="HalfVector2"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="HalfVector2"/> on the left side of the operand.</param>
/// The <see cref="HalfVector2"/> on the left side of the operand. /// <param name="right">The <see cref="HalfVector2"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="HalfVector2"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(HalfVector2 left, HalfVector2 right) public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right);
{
return !left.Equals(right);
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<HalfVector2> CreatePixelOperations() => new PixelOperations<HalfVector2>(); public PixelOperations<HalfVector2> CreatePixelOperations() => new PixelOperations<HalfVector2>();
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2 ToVector2()
{
Vector2 vector;
vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue);
vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10));
return vector;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector)
{ {
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
@ -109,7 +66,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4()
{ {
var scaled = this.ToVector2(); var scaled = this.ToVector2();
@ -119,14 +76,11 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y);
{
this.PackedValue = Pack(vector.X, vector.Y);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4()
{ {
var vector = this.ToVector2(); var vector = this.ToVector2();
@ -134,140 +88,82 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// Expands the packed representation into a <see cref="Vector2"/>.
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
/// <inheritdoc /> [MethodImpl(InliningOptions.ShortMethod)]
public override string ToString() public Vector2 ToVector2()
{ {
return this.ToVector2().ToString(); Vector2 vector;
vector.X = HalfTypeHelper.Unpack((ushort)this.PackedValue);
vector.Y = HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10));
return vector;
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) => obj is HalfVector2 other && this.Equals(other);
public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) [MethodImpl(InliningOptions.ShortMethod)]
{ public bool Equals(HalfVector2 other) => this.PackedValue.Equals(other.PackedValue);
return obj is HalfVector2 other && this.Equals(other);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString()
public bool Equals(HalfVector2 other)
{ {
return this.PackedValue.Equals(other.PackedValue); var vector = this.ToVector2();
return FormattableString.Invariant($"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})");
} }
/// <summary> /// <inheritdoc />
/// Packs the <see cref="float"/> components into a <see cref="uint"/>. [MethodImpl(InliningOptions.ShortMethod)]
/// </summary> public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param> [MethodImpl(InliningOptions.ShortMethod)]
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y) private static uint Pack(float x, float y)
{ {
uint num2 = HalfTypeHelper.Pack(x); uint num2 = HalfTypeHelper.Pack(x);
uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10); uint num = (uint)(HalfTypeHelper.Pack(y) << 0x10);
return num2 | num; return num2 | num;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
} }
} }

188
src/ImageSharp/PixelFormats/HalfVector4.cs

@ -15,16 +15,6 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong> public struct HalfVector4 : IPixel<HalfVector4>, IPackedVector<ulong>
{ {
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half vector value.
/// </summary>
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HalfVector4"/> struct. /// Initializes a new instance of the <see cref="HalfVector4"/> struct.
/// </summary> /// </summary>
@ -33,64 +23,46 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component.</param> /// <param name="z">The z-component.</param>
/// <param name="w">The w-component.</param> /// <param name="w">The w-component.</param>
public HalfVector4(float x, float y, float z, float w) public HalfVector4(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{ {
var vector = new Vector4(x, y, z, w);
this.PackedValue = Pack(ref vector);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="HalfVector4"/> struct. /// Initializes a new instance of the <see cref="HalfVector4"/> struct.
/// </summary> /// </summary>
/// <param name="vector">A vector containing the initial values for the components</param> /// <param name="vector">A vector containing the initial values for the components</param>
public HalfVector4(Vector4 vector) public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(ref vector);
}
/// <inheritdoc/> /// <inheritdoc/>
public ulong PackedValue { get; set; } public ulong PackedValue { get; set; }
/// <summary> /// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality. /// Compares two <see cref="HalfVector4"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="HalfVector4"/> on the left side of the operand.</param>
/// The <see cref="HalfVector2"/> on the left side of the operand. /// <param name="right">The <see cref="HalfVector4"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="HalfVector2"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(HalfVector4 left, HalfVector4 right) public static bool operator ==(HalfVector4 left, HalfVector4 right) => left.Equals(right);
{
return left.Equals(right);
}
/// <summary> /// <summary>
/// Compares two <see cref="HalfVector2"/> objects for equality. /// Compares two <see cref="HalfVector4"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="HalfVector4"/> on the left side of the operand.</param>
/// The <see cref="HalfVector2"/> on the left side of the operand. /// <param name="right">The <see cref="HalfVector4"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="HalfVector2"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(HalfVector4 left, HalfVector4 right) public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right);
{
return !left.Equals(right);
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<HalfVector4> CreatePixelOperations() => new PixelOperations<HalfVector4>(); public PixelOperations<HalfVector4> CreatePixelOperations() => new PixelOperations<HalfVector4>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector)
{ {
vector *= 2F; vector *= 2F;
@ -99,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4()
{ {
var scaled = this.ToVector4(); var scaled = this.ToVector4();
@ -109,14 +81,11 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(ref vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4()
{ {
return new Vector4( return new Vector4(
@ -127,124 +96,69 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override bool Equals(object obj) => obj is HalfVector4 other && this.Equals(other);
{
return this.ToVector4().ToString();
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode(); public bool Equals(HalfVector4 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override string ToString()
{ {
return obj is HalfVector4 other && this.Equals(other); var vector = this.ToVector4();
return FormattableString.Invariant($"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(HalfVector4 other) public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.Equals(other.PackedValue);
}
/// <summary> /// <summary>
/// Packs a <see cref="Vector4"/> into a <see cref="ulong"/>. /// Packs a <see cref="Vector4"/> into a <see cref="ulong"/>.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the values to pack.</param> /// <param name="vector">The vector containing the values to pack.</param>
/// <returns>The <see cref="ulong"/> containing the packed values.</returns> /// <returns>The <see cref="ulong"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
private static ulong Pack(ref Vector4 vector) private static ulong Pack(ref Vector4 vector)
{ {
ulong num4 = HalfTypeHelper.Pack(vector.X); ulong num4 = HalfTypeHelper.Pack(vector.X);
@ -253,15 +167,5 @@ namespace SixLabors.ImageSharp.PixelFormats
ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30; ulong num1 = (ulong)HalfTypeHelper.Pack(vector.W) << 0x30;
return num4 | num3 | num2 | num1; return num4 | num3 | num2 | num1;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
} }
} }

78
src/ImageSharp/PixelFormats/IPixel.cs

@ -28,12 +28,6 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public interface IPixel public interface IPixel
{ {
/// <summary>
/// Sets the packed representation from a <see cref="Vector4"/>.
/// </summary>
/// <param name="vector">The vector to create the packed representation from.</param>
void PackFromVector4(Vector4 vector);
/// <summary> /// <summary>
/// Sets the packed representation from a scaled <see cref="Vector4"/>. /// Sets the packed representation from a scaled <see cref="Vector4"/>.
/// </summary> /// </summary>
@ -48,6 +42,12 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>The <see cref="Vector4"/>.</returns> /// <returns>The <see cref="Vector4"/>.</returns>
Vector4 ToScaledVector4(); Vector4 ToScaledVector4();
/// <summary>
/// Sets the packed representation from a <see cref="Vector4"/>.
/// </summary>
/// <param name="vector">The vector to create the packed representation from.</param>
void PackFromVector4(Vector4 vector);
/// <summary> /// <summary>
/// Expands the packed representation into a <see cref="Vector4"/>. /// Expands the packed representation into a <see cref="Vector4"/>.
/// The vector components are typically expanded in least to greatest significance order. /// The vector components are typically expanded in least to greatest significance order.
@ -55,30 +55,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns>The <see cref="Vector4"/>.</returns> /// <returns>The <see cref="Vector4"/>.</returns>
Vector4 ToVector4(); Vector4 ToVector4();
/// <summary>
/// Packs the pixel from an <see cref="Rgba32"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgba32"/> value.</param>
void PackFromRgba32(Rgba32 source);
/// <summary>
/// Packs the pixel from an <see cref="Rgb48"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgb48"/> value.</param>
void PackFromRgb48(Rgb48 source);
/// <summary>
/// Packs the pixel from an <see cref="Rgba64"/> value.
/// </summary>
/// <param name="source">The <see cref="Rgba64"/> value.</param>
void PackFromRgba64(Rgba64 source);
/// <summary> /// <summary>
/// Packs the pixel from an <see cref="Argb32"/> value. /// Packs the pixel from an <see cref="Argb32"/> value.
/// </summary> /// </summary>
/// <param name="source">The <see cref="Argb32"/> value.</param> /// <param name="source">The <see cref="Argb32"/> value.</param>
void PackFromArgb32(Argb32 source); void PackFromArgb32(Argb32 source);
/// <summary>
/// Packs the pixel from an <see cref="Bgr24"/> value.
/// </summary>
/// <param name="source">The <see cref="Bgr24"/> value.</param>
void PackFromBgr24(Bgr24 source);
/// <summary> /// <summary>
/// Packs the pixel from an <see cref="Bgra32"/> value. /// Packs the pixel from an <see cref="Bgra32"/> value.
/// </summary> /// </summary>
@ -86,45 +74,45 @@ namespace SixLabors.ImageSharp.PixelFormats
void PackFromBgra32(Bgra32 source); void PackFromBgra32(Bgra32 source);
/// <summary> /// <summary>
/// Converts the pixel to <see cref="Rgb24"/> format. /// Packs the Pixel from an <see cref="Gray8"/> value.
/// </summary> /// </summary>
/// <param name="dest">The destination pixel to write to</param> /// <param name="source">The <see cref="Gray8"/> value.</param>
void ToRgb24(ref Rgb24 dest); void PackFromGray8(Gray8 source);
/// <summary> /// <summary>
/// Converts the pixel to <see cref="Rgba32"/> format. /// Packs the Pixel from an <see cref="Gray16"/> value.
/// </summary> /// </summary>
/// <param name="dest">The destination pixel to write to</param> /// <param name="source">The <see cref="Gray16"/> value.</param>
void ToRgba32(ref Rgba32 dest); void PackFromGray16(Gray16 source);
/// <summary> /// <summary>
/// Converts the pixel to <see cref="Rgb48"/> format. /// Packs the pixel from an <see cref="Rgb24"/> value.
/// </summary> /// </summary>
/// <param name="dest">The destination pixel to write to</param> /// <param name="source">The <see cref="Rgb24"/> value.</param>
void ToRgb48(ref Rgb48 dest); void PackFromRgb24(Rgb24 source);
/// <summary> /// <summary>
/// Converts the pixel to <see cref="Rgba64"/> format. /// Packs the pixel from an <see cref="Rgba32"/> value.
/// </summary> /// </summary>
/// <param name="dest">The destination pixel to write to</param> /// <param name="source">The <see cref="Rgba32"/> value.</param>
void ToRgba64(ref Rgba64 dest); void PackFromRgba32(Rgba32 source);
/// <summary> /// <summary>
/// Converts the pixel to <see cref="Argb32"/> format. /// Expands the packed representation into an <see cref="Rgba32"/>.
/// </summary> /// </summary>
/// <param name="dest">The destination pixel to write to</param> /// <returns>The <see cref="Rgba32"/>.</returns>
void ToArgb32(ref Argb32 dest); Rgba32 ToRgba32();
/// <summary> /// <summary>
/// Converts the pixel to <see cref="Bgr24"/> format. /// Packs the pixel from an <see cref="Rgb48"/> value.
/// </summary> /// </summary>
/// <param name="dest">The destination pixel to write to</param> /// <param name="source">The <see cref="Rgb48"/> value.</param>
void ToBgr24(ref Bgr24 dest); void PackFromRgb48(Rgb48 source);
/// <summary> /// <summary>
/// Converts the pixel to <see cref="Bgra32"/> format. /// Packs the pixel from an <see cref="Rgba64"/> value.
/// </summary> /// </summary>
/// <param name="dest">The destination pixel to write to</param> /// <param name="source">The <see cref="Rgba64"/> value.</param>
void ToBgra32(ref Bgra32 dest); void PackFromRgba64(Rgba64 source);
} }
} }

253
src/ImageSharp/PixelFormats/NormalizedByte2.cs

@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public struct NormalizedByte2 : IPixel<NormalizedByte2>, IPackedVector<ushort> public struct NormalizedByte2 : IPixel<NormalizedByte2>, IPackedVector<ushort>
{ {
/// <summary> private static readonly Vector2 Half = new Vector2(127);
/// The maximum byte value. private static readonly Vector2 MinusOne = new Vector2(-1F);
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector4 Half = new Vector4(127);
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector4 Round = new Vector4(.5F);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte2"/> struct. /// Initializes a new instance of the <see cref="NormalizedByte2"/> struct.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the component values.</param> /// <param name="x">The x-component.</param>
public NormalizedByte2(Vector2 vector) /// <param name="y">The y-component.</param>
public NormalizedByte2(float x, float y)
: this(new Vector2(x, y))
{ {
this.PackedValue = Pack(vector.X, vector.Y);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte2"/> struct. /// Initializes a new instance of the <see cref="NormalizedByte2"/> struct.
/// </summary> /// </summary>
/// <param name="x">The x-component.</param> /// <param name="vector">The vector containing the component values.</param>
/// <param name="y">The y-component.</param> public NormalizedByte2(Vector2 vector) => this.PackedValue = Pack(vector);
public NormalizedByte2(float x, float y)
{
this.PackedValue = Pack(x, y);
}
/// <inheritdoc/> /// <inheritdoc/>
public ushort PackedValue { get; set; } public ushort PackedValue { get; set; }
@ -55,66 +40,39 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Compares two <see cref="NormalizedByte2"/> objects for equality. /// Compares two <see cref="NormalizedByte2"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="NormalizedByte2"/> on the left side of the operand.</param>
/// The <see cref="NormalizedByte2"/> on the left side of the operand. /// <param name="right">The <see cref="NormalizedByte2"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="NormalizedByte2"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="NormalizedByte2"/> objects for equality. /// Compares two <see cref="NormalizedByte2"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="NormalizedByte2"/> on the left side of the operand.</param>
/// The <see cref="NormalizedByte2"/> on the left side of the operand. /// <param name="right">The <see cref="NormalizedByte2"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="NormalizedByte2"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<NormalizedByte2> CreatePixelOperations() => new PixelOperations<NormalizedByte2>(); public PixelOperations<NormalizedByte2> CreatePixelOperations() => new PixelOperations<NormalizedByte2>();
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2 ToVector2()
{
return new Vector2(
(sbyte)((this.PackedValue >> 0) & 0xFF) / 127F,
(sbyte)((this.PackedValue >> 8) & 0xFF) / 127F);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector)
{ {
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
scaled -= Vector2.One; scaled -= Vector2.One;
this.PackedValue = Pack(scaled.X, scaled.Y); this.PackedValue = Pack(scaled);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4()
{ {
var scaled = this.ToVector2(); var scaled = this.ToVector2();
@ -124,172 +82,97 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector)
{ {
this.PackedValue = Pack(vector.X, vector.Y); var vector2 = new Vector2(vector.X, vector.Y);
this.PackedValue = Pack(vector2);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F);
{
return new Vector4(this.ToVector2(), 0F, 1F);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// Expands the packed representation into a <see cref="Vector2"/>.
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <inheritdoc /> /// <returns>The <see cref="Vector2"/>.</returns>
public override bool Equals(object obj) [MethodImpl(InliningOptions.ShortMethod)]
public Vector2 ToVector2()
{ {
return obj is NormalizedByte2 other && this.Equals(other); return new Vector2(
(sbyte)((this.PackedValue >> 0) & 0xFF) / 127F,
(sbyte)((this.PackedValue >> 8) & 0xFF) / 127F);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) => obj is NormalizedByte2 other && this.Equals(other);
public bool Equals(NormalizedByte2 other)
{
return this.PackedValue == other.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(NormalizedByte2 other) => this.PackedValue.Equals(other.PackedValue);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode(); public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return this.PackedValue.ToString("X"); var vector = this.ToVector2();
return FormattableString.Invariant($"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})");
} }
/// <summary> [MethodImpl(InliningOptions.ShortMethod)]
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>. private static ushort Pack(Vector2 vector)
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <returns>The <see cref="ushort"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ushort Pack(float x, float y)
{ {
int byte2 = ((ushort)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; vector = Vector2.Clamp(vector, MinusOne, Vector2.One) * Half;
int byte1 = ((ushort)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8;
return (ushort)(byte2 | byte1); int byte2 = ((ushort)Math.Round(vector.X) & 0xFF) << 0;
} int byte1 = ((ushort)Math.Round(vector.Y) & 0xFF) << 8;
[MethodImpl(MethodImplOptions.AggressiveInlining)] return (ushort)(byte2 | byte1);
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
} }
} }
} }

234
src/ImageSharp/PixelFormats/NormalizedByte4.cs

@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public struct NormalizedByte4 : IPixel<NormalizedByte4>, IPackedVector<uint> public struct NormalizedByte4 : IPixel<NormalizedByte4>, IPackedVector<uint>
{ {
/// <summary>
/// The maximum byte value.
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector4 Half = new Vector4(127); private static readonly Vector4 Half = new Vector4(127);
private static readonly Vector4 MinusOne = new Vector4(-1F);
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector4 Round = new Vector4(.5F);
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte4"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedByte4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte4"/> struct. /// Initializes a new instance of the <see cref="NormalizedByte4"/> struct.
@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component.</param> /// <param name="z">The z-component.</param>
/// <param name="w">The w-component.</param> /// <param name="w">The w-component.</param>
public NormalizedByte4(float x, float y, float z, float w) public NormalizedByte4(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{ {
this.PackedValue = Pack(x, y, z, w);
} }
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedByte4"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/> /// <inheritdoc/>
public uint PackedValue { get; set; } public uint PackedValue { get; set; }
/// <summary> /// <summary>
/// Compares two <see cref="NormalizedByte4"/> objects for equality. /// Compares two <see cref="NormalizedByte4"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="NormalizedByte4"/> on the left side of the operand.</param>
/// The <see cref="NormalizedByte4"/> on the left side of the operand. /// <param name="right">The <see cref="NormalizedByte4"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="NormalizedByte4"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="NormalizedByte4"/> objects for equality. /// Compares two <see cref="NormalizedByte4"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="NormalizedByte4"/> on the left side of the operand.</param>
/// The <see cref="NormalizedByte4"/> on the left side of the operand. /// <param name="right">The <see cref="NormalizedByte4"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="NormalizedByte4"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<NormalizedByte4> CreatePixelOperations() => new PixelOperations<NormalizedByte4>(); public PixelOperations<NormalizedByte4> CreatePixelOperations() => new PixelOperations<NormalizedByte4>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector)
{ {
vector *= 2F; vector *= 2F;
@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4()
{ {
var scaled = this.ToVector4(); var scaled = this.ToVector4();
@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4()
{ {
return new Vector4( return new Vector4(
@ -131,162 +99,74 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromArgb32(Argb32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromBgra32(Bgra32 source)
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4(); /// <inheritdoc/>
dest.R = (byte)vector.X; [MethodImpl(InliningOptions.ShortMethod)]
dest.G = (byte)vector.Y; public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W; /// <inheritdoc/>
} [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is NormalizedByte4 other && this.Equals(other);
{
return obj is NormalizedByte4 other && this.Equals(other);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(NormalizedByte4 other) public bool Equals(NormalizedByte4 other) => this.PackedValue.Equals(other.PackedValue);
{
return this.PackedValue == other.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() => this.PackedValue.GetHashCode(); public override int GetHashCode() => this.PackedValue.GetHashCode();
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return this.PackedValue.ToString("X"); var vector = this.ToVector4();
return FormattableString.Invariant($"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
} }
/// <summary> [MethodImpl(InliningOptions.ShortMethod)]
/// Packs the <see cref="float"/> components into a <see cref="uint"/>. private static uint Pack(ref Vector4 vector)
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y, float z, float w)
{ {
uint byte4 = ((uint)Math.Round(x.Clamp(-1F, 1F) * 127F) & 0xFF) << 0; vector = Vector4.Clamp(vector, MinusOne, Vector4.One) * Half;
uint byte3 = ((uint)Math.Round(y.Clamp(-1F, 1F) * 127F) & 0xFF) << 8;
uint byte2 = ((uint)Math.Round(z.Clamp(-1F, 1F) * 127F) & 0xFF) << 16;
uint byte1 = ((uint)Math.Round(w.Clamp(-1F, 1F) * 127F) & 0xFF) << 24;
return byte4 | byte3 | byte2 | byte1; uint byte4 = ((uint)Math.Round(vector.X) & 0xFF) << 0;
} uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 8;
uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 16;
uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 24;
[MethodImpl(MethodImplOptions.AggressiveInlining)] return byte4 | byte3 | byte2 | byte1;
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
} }
} }
} }

239
src/ImageSharp/PixelFormats/NormalizedShort2.cs

@ -15,39 +15,24 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public struct NormalizedShort2 : IPixel<NormalizedShort2>, IPackedVector<uint> public struct NormalizedShort2 : IPixel<NormalizedShort2>, IPackedVector<uint>
{ {
/// <summary> private static readonly Vector2 Max = new Vector2(0x7FFF);
/// The maximum byte value. private static readonly Vector2 Min = Vector2.Negate(Max);
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector4 Half = new Vector4(127);
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector4 Round = new Vector4(.5F);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort2"/> struct. /// Initializes a new instance of the <see cref="NormalizedShort2"/> struct.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the component values.</param> /// <param name="x">The x-component.</param>
public NormalizedShort2(Vector2 vector) /// <param name="y">The y-component.</param>
public NormalizedShort2(float x, float y)
: this(new Vector2(x, y))
{ {
this.PackedValue = Pack(vector.X, vector.Y);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort2"/> struct. /// Initializes a new instance of the <see cref="NormalizedShort2"/> struct.
/// </summary> /// </summary>
/// <param name="x">The x-component.</param> /// <param name="vector">The vector containing the component values.</param>
/// <param name="y">The y-component.</param> public NormalizedShort2(Vector2 vector) => this.PackedValue = Pack(vector);
public NormalizedShort2(float x, float y)
{
this.PackedValue = Pack(x, y);
}
/// <inheritdoc/> /// <inheritdoc/>
public uint PackedValue { get; set; } public uint PackedValue { get; set; }
@ -55,53 +40,39 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Compares two <see cref="NormalizedShort2"/> objects for equality. /// Compares two <see cref="NormalizedShort2"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="NormalizedShort2"/> on the left side of the operand.</param>
/// The <see cref="NormalizedShort2"/> on the left side of the operand. /// <param name="right">The <see cref="NormalizedShort2"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="NormalizedShort2"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) => left.Equals(right);
{
return left.Equals(right);
}
/// <summary> /// <summary>
/// Compares two <see cref="NormalizedShort2"/> objects for equality. /// Compares two <see cref="NormalizedShort2"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="NormalizedShort2"/> on the left side of the operand.</param>
/// The <see cref="NormalizedShort2"/> on the left side of the operand. /// <param name="right">The <see cref="NormalizedShort2"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="NormalizedShort2"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right);
{
return !left.Equals(right);
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<NormalizedShort2> CreatePixelOperations() => new PixelOperations<NormalizedShort2>(); public PixelOperations<NormalizedShort2> CreatePixelOperations() => new PixelOperations<NormalizedShort2>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector)
{ {
Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F;
scaled -= Vector2.One; scaled -= Vector2.One;
this.PackedValue = Pack(scaled.X, scaled.Y); this.PackedValue = Pack(scaled);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4()
{ {
var scaled = this.ToVector2(); var scaled = this.ToVector2();
@ -111,130 +82,63 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector)
{ {
this.PackedValue = Pack(vector.X, vector.Y); var vector2 = new Vector2(vector.X, vector.Y);
this.PackedValue = Pack(vector2);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0, 1);
{
return new Vector4(this.ToVector2(), 0, 1);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = 0;
dest.A = 255;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <summary> /// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>. /// Expands the packed representation into a <see cref="Vector2"/>.
/// The vector components are typically expanded in least to greatest significance order. /// The vector components are typically expanded in least to greatest significance order.
/// </summary> /// </summary>
/// <returns>The <see cref="Vector2"/>.</returns> /// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector2 ToVector2() public Vector2 ToVector2()
{ {
const float MaxVal = 0x7FFF; const float MaxVal = 0x7FFF;
@ -245,61 +149,34 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is NormalizedShort2 other && this.Equals(other);
{
return obj is NormalizedShort2 other && this.Equals(other);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(NormalizedShort2 other) public bool Equals(NormalizedShort2 other) => this.PackedValue.Equals(other.PackedValue);
{
return this.PackedValue.Equals(other.PackedValue);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return this.PackedValue.ToString("X"); var vector = this.ToVector2();
return FormattableString.Invariant($"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})");
} }
/// <summary> [MethodImpl(InliningOptions.ShortMethod)]
/// Packs the <see cref="float"/> components into a <see cref="uint"/>. private static uint Pack(Vector2 vector)
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y)
{ {
const float MaxPos = 0x7FFF; vector *= Max;
const float MinNeg = -MaxPos; vector = Vector2.Clamp(vector, Min, Max);
// Clamp the value between min and max values
// Round rather than truncate. // Round rather than truncate.
uint word2 = (uint)((int)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF); uint word2 = (uint)((int)MathF.Round(vector.X) & 0xFFFF);
uint word1 = (uint)(((int)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10); uint word1 = (uint)(((int)MathF.Round(vector.Y) & 0xFFFF) << 0x10);
return word2 | word1; return word2 | word1;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
} }
} }

243
src/ImageSharp/PixelFormats/NormalizedShort4.cs

@ -15,29 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public struct NormalizedShort4 : IPixel<NormalizedShort4>, IPackedVector<ulong> public struct NormalizedShort4 : IPixel<NormalizedShort4>, IPackedVector<ulong>
{ {
/// <summary> private static readonly Vector4 Max = new Vector4(0x7FFF);
/// The maximum byte value. private static readonly Vector4 Min = Vector4.Negate(Max);
/// </summary>
private static readonly Vector4 MaxBytes = new Vector4(255);
/// <summary>
/// The half the maximum byte value.
/// </summary>
private static readonly Vector4 Half = new Vector4(127);
/// <summary>
/// The vector value used for rounding.
/// </summary>
private static readonly Vector4 Round = new Vector4(.5F);
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort4"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedShort4(Vector4 vector)
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort4"/> struct. /// Initializes a new instance of the <see cref="NormalizedShort4"/> struct.
@ -47,54 +26,46 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component.</param> /// <param name="z">The z-component.</param>
/// <param name="w">The w-component.</param> /// <param name="w">The w-component.</param>
public NormalizedShort4(float x, float y, float z, float w) public NormalizedShort4(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{ {
this.PackedValue = Pack(x, y, z, w);
} }
/// <summary>
/// Initializes a new instance of the <see cref="NormalizedShort4"/> struct.
/// </summary>
/// <param name="vector">The vector containing the component values.</param>
public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(ref vector);
/// <inheritdoc/> /// <inheritdoc/>
public ulong PackedValue { get; set; } public ulong PackedValue { get; set; }
/// <summary> /// <summary>
/// Compares two <see cref="NormalizedShort4"/> objects for equality. /// Compares two <see cref="NormalizedShort4"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="NormalizedShort4"/> on the left side of the operand.</param>
/// The <see cref="NormalizedShort4"/> on the left side of the operand. /// <param name="right">The <see cref="NormalizedShort4"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="NormalizedShort4"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) => left.Equals(right);
{
return left.Equals(right);
}
/// <summary> /// <summary>
/// Compares two <see cref="NormalizedShort4"/> objects for equality. /// Compares two <see cref="NormalizedShort4"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="NormalizedShort4"/> on the left side of the operand.</param>
/// The <see cref="NormalizedShort4"/> on the left side of the operand. /// <param name="right">The <see cref="NormalizedShort4"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="NormalizedShort4"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right);
{
return !left.Equals(right);
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<NormalizedShort4> CreatePixelOperations() => new PixelOperations<NormalizedShort4>(); public PixelOperations<NormalizedShort4> CreatePixelOperations() => new PixelOperations<NormalizedShort4>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector)
{ {
vector *= 2F; vector *= 2F;
@ -103,7 +74,7 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4()
{ {
var scaled = this.ToVector4(); var scaled = this.ToVector4();
@ -113,14 +84,11 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4()
{ {
const float MaxVal = 0x7FFF; const float MaxVal = 0x7FFF;
@ -133,169 +101,76 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = source.ToByteScaledVector4();
vector -= Round;
vector -= Half;
vector -= Round;
vector /= Half;
this.PackFromVector4(vector);
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is NormalizedShort4 other && this.Equals(other);
{
return obj is NormalizedShort4 other && this.Equals(other);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(NormalizedShort4 other) public bool Equals(NormalizedShort4 other) => this.PackedValue.Equals(other.PackedValue);
{
return this.PackedValue.Equals(other.PackedValue);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return this.PackedValue.ToString("X"); var vector = this.ToVector4();
return FormattableString.Invariant($"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
} }
/// <summary> [MethodImpl(InliningOptions.ShortMethod)]
/// Packs the <see cref="float"/> components into a <see cref="ulong"/>. private static ulong Pack(ref Vector4 vector)
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
/// <returns>The <see cref="ulong"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static ulong Pack(float x, float y, float z, float w)
{ {
const float MaxPos = 0x7FFF; vector *= Max;
const float MinNeg = -MaxPos; vector = Vector4.Clamp(vector, Min, Max);
// Clamp the value between min and max values // Round rather than truncate.
ulong word4 = ((ulong)MathF.Round(x * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x00; ulong word4 = ((ulong)MathF.Round(vector.X) & 0xFFFF) << 0x00;
ulong word3 = ((ulong)MathF.Round(y * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x10; ulong word3 = ((ulong)MathF.Round(vector.Y) & 0xFFFF) << 0x10;
ulong word2 = ((ulong)MathF.Round(z * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x20; ulong word2 = ((ulong)MathF.Round(vector.Z) & 0xFFFF) << 0x20;
ulong word1 = ((ulong)MathF.Round(w * MaxPos).Clamp(MinNeg, MaxPos) & 0xFFFF) << 0x30; ulong word1 = ((ulong)MathF.Round(vector.W) & 0xFFFF) << 0x30;
return word4 | word3 | word2 | word1; return word4 | word3 | word2 | word1;
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4()
{
var vector = this.ToVector4();
vector *= Half;
vector += Round;
vector += Half;
vector += Round;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
return vector;
}
} }
} }

54
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs

@ -105,6 +105,60 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
} }
/// <summary>
/// Performs a bulk conversion of a collection of one pixel format into another.
/// </summary>
/// <typeparam name="TPixel2">The pixel format.</typeparam>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destinationColors">The <see cref="Span{T}"/> to the destination colors.</param>
/// <param name="count">The number of pixels to convert.</param>
internal virtual void To<TPixel2>(ReadOnlySpan<TPixel> sourceColors, Span<TPixel2> destinationColors, int count)
where TPixel2 : struct, IPixel<TPixel2>
{
GuardSpans(sourceColors, nameof(sourceColors), destinationColors, nameof(destinationColors), count);
ref TPixel sourceRef = ref MemoryMarshal.GetReference(sourceColors);
// Gray8 and Gray16 are special implementations of IPixel in that they do not conform to the
// standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 alogrithm.
// One of the requirements of PackFromScaledVector4/ToScaledVector4 is that it unaware of this and
// packs/unpacks the pixel without and conversion so we employ custom methods do do this.
if (typeof(TPixel2).Equals(typeof(Gray16)))
{
ref Gray16 gray16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<TPixel2, Gray16>(destinationColors));
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray16 dp = ref Unsafe.Add(ref gray16Ref, i);
dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4());
}
return;
}
if (typeof(TPixel2).Equals(typeof(Gray8)))
{
ref Gray8 gray8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast<TPixel2, Gray8>(destinationColors));
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref Gray8 dp = ref Unsafe.Add(ref gray8Ref, i);
dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4());
}
return;
}
// Normal converson
ref TPixel2 destRef = ref MemoryMarshal.GetReference(destinationColors);
for (int i = 0; i < count; i++)
{
ref TPixel sp = ref Unsafe.Add(ref sourceRef, i);
ref TPixel2 dp = ref Unsafe.Add(ref destRef, i);
dp.PackFromScaledVector4(sp.ToScaledVector4());
}
}
/// <summary> /// <summary>
/// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size. /// Verifies that the given 'source' and 'destination' spans are at least of 'minLength' size.
/// Throwing an <see cref="ArgumentException"/> if the condition is not met. /// Throwing an <see cref="ArgumentException"/> if the condition is not met.

216
src/ImageSharp/PixelFormats/Rg32.cs

@ -15,24 +15,23 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public struct Rg32 : IPixel<Rg32>, IPackedVector<uint> public struct Rg32 : IPixel<Rg32>, IPackedVector<uint>
{ {
private static readonly Vector2 Max = new Vector2(ushort.MaxValue);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Rg32"/> struct. /// Initializes a new instance of the <see cref="Rg32"/> struct.
/// </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>
public Rg32(float x, float y) public Rg32(float x, float y)
: this(new Vector2(x, y))
{ {
this.PackedValue = Pack(x, y);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Rg32"/> struct. /// Initializes a new instance of the <see cref="Rg32"/> struct.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the component values.</param> /// <param name="vector">The vector containing the component values.</param>
public Rg32(Vector2 vector) public Rg32(Vector2 vector) => this.PackedValue = Pack(vector);
{
this.PackedValue = Pack(vector.X, vector.Y);
}
/// <inheritdoc/> /// <inheritdoc/>
public uint PackedValue { get; set; } public uint PackedValue { get; set; }
@ -40,214 +39,119 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Compares two <see cref="Rg32"/> objects for equality. /// Compares two <see cref="Rg32"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="Rg32"/> on the left side of the operand.</param>
/// The <see cref="Rg32"/> on the left side of the operand. /// <param name="right">The <see cref="Rg32"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="Rg32"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rg32 left, Rg32 right) public static bool operator ==(Rg32 left, Rg32 right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="Rg32"/> objects for equality. /// Compares two <see cref="Rg32"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="Rg32"/> on the left side of the operand.</param>
/// The <see cref="Rg32"/> on the left side of the operand. /// <param name="right">The <see cref="Rg32"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="Rg32"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rg32 left, Rg32 right) public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<Rg32> CreatePixelOperations() => new PixelOperations<Rg32>(); public PixelOperations<Rg32> CreatePixelOperations() => new PixelOperations<Rg32>();
/// <summary>
/// Expands the packed representation into a <see cref="Vector2"/>.
/// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector2 ToVector2()
{
return new Vector2(
(this.PackedValue & 0xFFFF) / 65535F,
((this.PackedValue >> 16) & 0xFFFF) / 65535F);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
this.PackFromVector4(vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4() => this.ToVector4();
{
return this.ToVector4();
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector)
{ {
this.PackedValue = Pack(vector.X, vector.Y); var vector2 = new Vector2(vector.X, vector.Y);
this.PackedValue = Pack(vector2);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public Vector4 ToVector4() => new Vector4(this.ToVector2(), 0F, 1F);
{
return new Vector4(this.ToVector2(), 0F, 1F);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToByteScaledVector4();
dest.R = (byte)vector.X;
dest.G = (byte)vector.Y;
dest.B = (byte)vector.Z;
dest.A = (byte)vector.W;
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// Expands the packed representation into a <see cref="Vector2"/>.
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// The vector components are typically expanded in least to greatest significance order.
/// </summary>
/// <returns>The <see cref="Vector2"/>.</returns>
[MethodImpl(InliningOptions.ShortMethod)]
public Vector2 ToVector2() => new Vector2(this.PackedValue & 0xFFFF, (this.PackedValue >> 16) & 0xFFFF) / Max;
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is Rg32 other && this.Equals(other);
{
return obj is Rg32 other && this.Equals(other);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rg32 other) public bool Equals(Rg32 other) => this.PackedValue.Equals(other.PackedValue);
{
return this.PackedValue == other.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return this.ToVector2().ToString(); var vector = this.ToVector2();
return FormattableString.Invariant($"Rg32({vector.X:#0.##}, {vector.Y:#0.##})");
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <summary> [MethodImpl(InliningOptions.ShortMethod)]
/// Packs the <see cref="float"/> components into a <see cref="uint"/>. private static uint Pack(Vector2 vector)
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y)
{ {
return (uint)( vector = Vector2.Clamp(vector, Vector2.Zero, Vector2.One) * Max;
((int)Math.Round(x.Clamp(0, 1) * 65535F) & 0xFFFF) | return (uint)(((int)Math.Round(vector.X) & 0xFFFF) | (((int)Math.Round(vector.Y) & 0xFFFF) << 16));
(((int)Math.Round(y.Clamp(0, 1) * 65535F) & 0xFFFF) << 16));
} }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4() => this.ToVector4() * 255F;
} }
} }

186
src/ImageSharp/PixelFormats/Rgb24.cs

@ -1,7 +1,6 @@
// Copyright (c) Six Labors and contributors. // Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0. // Licensed under the Apache License, Version 2.0.
using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
@ -16,7 +15,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </para> /// </para>
/// </summary> /// </summary>
[StructLayout(LayoutKind.Explicit)] [StructLayout(LayoutKind.Explicit)]
public struct Rgb24 : IPixel<Rgb24> public partial struct Rgb24 : IPixel<Rgb24>
{ {
/// <summary> /// <summary>
/// The red component. /// The red component.
@ -36,13 +35,16 @@ namespace SixLabors.ImageSharp.PixelFormats
[FieldOffset(2)] [FieldOffset(2)]
public byte B; public byte B;
private static readonly Vector4 MaxBytes = new Vector4(byte.MaxValue);
private static readonly Vector4 Half = new Vector4(0.5F);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Rgb24"/> struct. /// Initializes a new instance of the <see cref="Rgb24"/> struct.
/// </summary> /// </summary>
/// <param name="r">The red component.</param> /// <param name="r">The red component.</param>
/// <param name="g">The green component.</param> /// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param> /// <param name="b">The blue component.</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Rgb24(byte r, byte g, byte b) public Rgb24(byte r, byte g, byte b)
{ {
this.R = r; this.R = r;
@ -56,48 +58,59 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
/// <param name="color">The instance of <see cref="ColorSpaces.Rgb"/> to convert.</param> /// <param name="color">The instance of <see cref="ColorSpaces.Rgb"/> to convert.</param>
/// <returns>An instance of <see cref="Rgb24"/>.</returns> /// <returns>An instance of <see cref="Rgb24"/>.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static implicit operator Rgb24(ColorSpaces.Rgb color) public static implicit operator Rgb24(ColorSpaces.Rgb color)
{ {
var vector = new Vector4(color.ToVector3(), 1); var vector = new Vector4(color.ToVector3(), 1F);
Rgb24 rgb = default; Rgb24 rgb = default;
rgb.PackFromScaledVector4(vector); rgb.PackFromScaledVector4(vector);
return rgb; return rgb;
} }
/// <summary>
/// Compares two <see cref="Rgb24"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Rgb24"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgb24"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rgb24 left, Rgb24 right) => left.Equals(right);
/// <summary>
/// Compares two <see cref="Rgb24"/> objects for equality.
/// </summary>
/// <param name="left">The <see cref="Rgb24"/> on the left side of the operand.</param>
/// <param name="right">The <see cref="Rgb24"/> on the right side of the operand.</param>
/// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns>
[MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right);
/// <inheritdoc/> /// <inheritdoc/>
public PixelOperations<Rgb24> CreatePixelOperations() => new PixelOperations<Rgb24>(); public PixelOperations<Rgb24> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rgb24 other) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
return this.R == other.R && this.G == other.G && this.B == other.B;
}
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) [MethodImpl(InliningOptions.ShortMethod)]
{ public Vector4 ToScaledVector4() => this.ToVector4();
return obj is Rgb24 other && this.Equals(other);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() public void PackFromVector4(Vector4 vector) => this.Pack(ref vector);
{
int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
return HashHelpers.Combine(hash, this.B.GetHashCode());
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4();
{
this = Unsafe.As<Rgba32, Rgb24>(ref source);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromArgb32(Argb32 source)
{ {
this.R = source.R; this.R = source.R;
@ -106,8 +119,8 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgr24(Bgr24 source)
{ {
this.R = source.R; this.R = source.R;
this.G = source.G; this.G = source.G;
@ -115,102 +128,95 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromBgra32(Bgra32 source)
{
this.PackFromVector4(vector);
}
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public Vector4 ToScaledVector4()
{ {
return this.ToVector4(); this.R = source.R;
this.G = source.G;
this.B = source.B;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public void PackFromGray8(Gray8 source)
{ {
Rgba32 rgba = default; this.R = source.PackedValue;
rgba.PackFromVector4(vector); this.G = source.PackedValue;
this.PackFromRgba32(rgba); this.B = source.PackedValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public void PackFromGray16(Gray16 source)
{ {
return new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); byte rgb = ImageMaths.DownScaleFrom16BitTo8Bit(source.PackedValue);
this.R = rgb;
this.G = rgb;
this.B = rgb;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) => dest = this; public void PackFromRgb24(Rgb24 source) => this = source;
/// <inheritdoc/> /// <inheritdoc/>
public void ToRgba32(ref Rgba32 dest) [MethodImpl(InliningOptions.ShortMethod)]
{ public void PackFromRgba32(Rgba32 source) => this = source.Rgb;
dest.Rgb = this;
dest.A = byte.MaxValue;
}
/// <inheritdoc/> /// <inheritdoc />
public void ToArgb32(ref Argb32 dest) [MethodImpl(InliningOptions.ShortMethod)]
{ public Rgba32 ToRgba32() => new Rgba32(this.R, this.G, this.B, byte.MaxValue);
dest.R = this.R;
dest.G = this.G;
dest.B = this.B;
dest.A = byte.MaxValue;
}
/// <inheritdoc/> /// <inheritdoc/>
public void ToBgr24(ref Bgr24 dest) [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source)
{ {
dest.R = this.R; this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
dest.G = this.G; this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
dest.B = this.B; this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
} }
/// <inheritdoc/> /// <inheritdoc/>
public void ToBgra32(ref Bgra32 dest) [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source)
{ {
dest.R = this.R; this.R = ImageMaths.DownScaleFrom16BitTo8Bit(source.R);
dest.G = this.G; this.G = ImageMaths.DownScaleFrom16BitTo8Bit(source.G);
dest.B = this.B; this.B = ImageMaths.DownScaleFrom16BitTo8Bit(source.B);
dest.A = byte.MaxValue;
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) => obj is Rgb24 other && this.Equals(other);
public void PackFromRgb48(Rgb48 source)
{
this.R = (byte)(((source.R * 255) + 32895) >> 16);
this.G = (byte)(((source.G * 255) + 32895) >> 16);
this.B = (byte)(((source.B * 255) + 32895) >> 16);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); public bool Equals(Rgb24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) public override int GetHashCode()
{ {
this.R = (byte)(((source.R * 255) + 32895) >> 16); int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
this.G = (byte)(((source.G * 255) + 32895) >> 16); return HashHelpers.Combine(hash, this.B.GetHashCode());
this.B = (byte)(((source.B * 255) + 32895) >> 16);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] public override string ToString() => $"Rgb24({this.R}, {this.G}, {this.B})";
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/> /// <summary>
public override string ToString() /// Packs a <see cref="Vector4"/> into a color.
/// </summary>
/// <param name="vector">The vector containing the values to pack.</param>
[MethodImpl(InliningOptions.ShortMethod)]
private void Pack(ref Vector4 vector)
{ {
return $"({this.R},{this.G},{this.B})"; vector *= MaxBytes;
vector += Half;
vector = Vector4.Clamp(vector, Vector4.Zero, MaxBytes);
this.R = (byte)vector.X;
this.G = (byte)vector.Y;
this.B = (byte)vector.Z;
} }
} }
} }

189
src/ImageSharp/PixelFormats/Rgb48.cs

@ -15,9 +15,9 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </para> /// </para>
/// </summary> /// </summary>
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public struct Rgb48 : IPixel<Rgb48> public partial struct Rgb48 : IPixel<Rgb48>
{ {
private const float Max = 65535F; private const float Max = ushort.MaxValue;
/// <summary> /// <summary>
/// Gets or sets the red component. /// Gets or sets the red component.
@ -48,29 +48,6 @@ namespace SixLabors.ImageSharp.PixelFormats
this.B = b; this.B = b;
} }
/// <summary>
/// Initializes a new instance of the <see cref="Rgb48"/> struct.
/// </summary>
/// <param name="r">The red component.</param>
/// <param name="g">The green component.</param>
/// <param name="b">The blue component.</param>
public Rgb48(float r, float g, float b)
: this()
{
this.R = (ushort)MathF.Round(r.Clamp(0, 1) * Max);
this.G = (ushort)MathF.Round(g.Clamp(0, 1) * Max);
this.B = (ushort)MathF.Round(b.Clamp(0, 1) * Max);
}
/// <summary>
/// Initializes a new instance of the <see cref="Rgb48"/> struct.
/// </summary>
/// <param name="vector">The vector containing the components values.</param>
public Rgb48(Vector3 vector)
: this(vector.X, vector.Y, vector.Z)
{
}
/// <summary> /// <summary>
/// Compares two <see cref="Rgb48"/> objects for equality. /// Compares two <see cref="Rgb48"/> objects for equality.
/// </summary> /// </summary>
@ -79,13 +56,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rgb48 left, Rgb48 right) public static bool operator ==(Rgb48 left, Rgb48 right) => left.Equals(right);
{
return left.R == right.R
&& left.G == right.G
&& left.B == right.B;
}
/// <summary> /// <summary>
/// Compares two <see cref="Rgb48"/> objects for equality. /// Compares two <see cref="Rgb48"/> objects for equality.
@ -95,40 +67,22 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rgb48 left, Rgb48 right) public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right);
{
return left.R != right.R
|| left.G != right.G
|| left.B != right.B;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<Rgb48> CreatePixelOperations() => new PixelOperations<Rgb48>(); public PixelOperations<Rgb48> CreatePixelOperations() => new PixelOperations();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
this.PackFromVector4(vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4() => this.ToVector4();
{
return this.ToVector4();
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4()
{
return new Vector4(this.R / Max, this.G / Max, this.B / Max, 1);
}
/// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromVector4(Vector4 vector) public void PackFromVector4(Vector4 vector)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max; vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Max;
@ -138,114 +92,103 @@ namespace SixLabors.ImageSharp.PixelFormats
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public Vector4 ToVector4() => new Vector4(this.R / Max, this.G / Max, this.B / Max, 1F);
/// <inheritdoc />
[MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source)
{ {
this.PackFromVector4(source.ToVector4()); this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source)
{ {
this.PackFromVector4(source.ToVector4()); this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source)
{ {
this.PackFromVector4(source.ToVector4()); this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba64(Rgba64 source) => this = source.Rgb; public void PackFromRgba64(Rgba64 source) => this = source.Rgb;
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source)
{ {
dest.R = (byte)(((this.R * 255) + 32895) >> 16); ushort rgb = ImageMaths.UpscaleFrom8BitTo16Bit(source.PackedValue);
dest.G = (byte)(((this.G * 255) + 32895) >> 16); this.R = rgb;
dest.B = (byte)(((this.B * 255) + 32895) >> 16); this.G = rgb;
this.B = rgb;
} }
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source)
{ {
dest.R = (byte)(((this.R * 255) + 32895) >> 16); this.R = source.PackedValue;
dest.G = (byte)(((this.G * 255) + 32895) >> 16); this.G = source.PackedValue;
dest.B = (byte)(((this.B * 255) + 32895) >> 16); this.B = source.PackedValue;
dest.A = 255;
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source)
{ {
dest.R = (byte)(((this.R * 255) + 32895) >> 16); this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
dest.G = (byte)(((this.G * 255) + 32895) >> 16); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
dest.B = (byte)(((this.B * 255) + 32895) >> 16); this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
dest.A = 255;
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source)
{ {
dest.R = (byte)(((this.R * 255) + 32895) >> 16); this.R = ImageMaths.UpscaleFrom8BitTo16Bit(source.R);
dest.G = (byte)(((this.G * 255) + 32895) >> 16); this.G = ImageMaths.UpscaleFrom8BitTo16Bit(source.G);
dest.B = (byte)(((this.B * 255) + 32895) >> 16); this.B = ImageMaths.UpscaleFrom8BitTo16Bit(source.B);
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32()
{ {
dest.R = (byte)(((this.R * 255) + 32895) >> 16); byte r = ImageMaths.DownScaleFrom16BitTo8Bit(this.R);
dest.G = (byte)(((this.G * 255) + 32895) >> 16); byte g = ImageMaths.DownScaleFrom16BitTo8Bit(this.G);
dest.B = (byte)(((this.B * 255) + 32895) >> 16); byte b = ImageMaths.DownScaleFrom16BitTo8Bit(this.B);
dest.A = 255; return new Rgba32(r, g, b, byte.MaxValue);
} }
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this = source; public void PackFromRgb48(Rgb48 source) => this = source;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgb48(ref Rgb48 dest) => dest = this;
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest)
{
dest.Rgb = this;
dest.A = ushort.MaxValue;
}
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is Rgb48 rgb48 && this.Equals(rgb48);
{
return obj is Rgb48 rgb48 && this.Equals(rgb48);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rgb48 other) public bool Equals(Rgb48 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B);
{
return this.R == other.R
&& this.G == other.G
&& this.B == other.B;
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() => this.ToVector4().ToString(); public override string ToString() => $"Rgb48({this.R}, {this.G}, {this.B})";
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() public override int GetHashCode()
{ {
return HashHelpers.Combine( return HashHelpers.Combine(

208
src/ImageSharp/PixelFormats/Rgba1010102.cs

@ -16,6 +16,8 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
public struct Rgba1010102 : IPixel<Rgba1010102>, IPackedVector<uint> public struct Rgba1010102 : IPixel<Rgba1010102>, IPackedVector<uint>
{ {
private static readonly Vector4 Multiplier = new Vector4(1023F, 1023F, 1023F, 3F);
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Rgba1010102"/> struct. /// Initializes a new instance of the <see cref="Rgba1010102"/> struct.
/// </summary> /// </summary>
@ -24,18 +26,15 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <param name="z">The z-component</param> /// <param name="z">The z-component</param>
/// <param name="w">The w-component</param> /// <param name="w">The w-component</param>
public Rgba1010102(float x, float y, float z, float w) public Rgba1010102(float x, float y, float z, float w)
: this(new Vector4(x, y, z, w))
{ {
this.PackedValue = Pack(x, y, z, w);
} }
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="Rgba1010102"/> struct. /// Initializes a new instance of the <see cref="Rgba1010102"/> struct.
/// </summary> /// </summary>
/// <param name="vector">The vector containing the component values.</param> /// <param name="vector">The vector containing the component values.</param>
public Rgba1010102(Vector4 vector) public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W);
}
/// <inheritdoc/> /// <inheritdoc/>
public uint PackedValue { get; set; } public uint PackedValue { get; set; }
@ -43,206 +42,119 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// Compares two <see cref="Rgba1010102"/> objects for equality. /// Compares two <see cref="Rgba1010102"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="Rgba1010102"/> on the left side of the operand.</param>
/// The <see cref="Rgba1010102"/> on the left side of the operand. /// <param name="right">The <see cref="Rgba1010102"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="Rgba1010102"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator ==(Rgba1010102 left, Rgba1010102 right) public static bool operator ==(Rgba1010102 left, Rgba1010102 right) => left.Equals(right);
{
return left.PackedValue == right.PackedValue;
}
/// <summary> /// <summary>
/// Compares two <see cref="Rgba1010102"/> objects for equality. /// Compares two <see cref="Rgba1010102"/> objects for equality.
/// </summary> /// </summary>
/// <param name="left"> /// <param name="left">The <see cref="Rgba1010102"/> on the left side of the operand.</param>
/// The <see cref="Rgba1010102"/> on the left side of the operand. /// <param name="right">The <see cref="Rgba1010102"/> on the right side of the operand.</param>
/// </param>
/// <param name="right">
/// The <see cref="Rgba1010102"/> on the right side of the operand.
/// </param>
/// <returns> /// <returns>
/// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false. /// True if the <paramref name="left"/> parameter is not equal to the <paramref name="right"/> parameter; otherwise, false.
/// </returns> /// </returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public static bool operator !=(Rgba1010102 left, Rgba1010102 right) public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right);
{
return left.PackedValue != right.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public PixelOperations<Rgba1010102> CreatePixelOperations() => new PixelOperations<Rgba1010102>(); public PixelOperations<Rgba1010102> CreatePixelOperations() => new PixelOperations<Rgba1010102>();
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromScaledVector4(Vector4 vector) public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector);
{
this.PackFromVector4(vector);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToScaledVector4() public Vector4 ToScaledVector4() => this.ToVector4();
{
return this.ToVector4();
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public Vector4 ToVector4() public void PackFromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector);
{
return new Vector4(
((this.PackedValue >> 0) & 0x03FF) / 1023F,
((this.PackedValue >> 10) & 0x03FF) / 1023F,
((this.PackedValue >> 20) & 0x03FF) / 1023F,
((this.PackedValue >> 30) & 0x03) / 3F);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromVector4(Vector4 vector) public Vector4 ToVector4()
{ {
this.PackedValue = Pack(vector.X, vector.Y, vector.Z, vector.W); return new Vector4(
(this.PackedValue >> 0) & 0x03FF,
(this.PackedValue >> 10) & 0x03FF,
(this.PackedValue >> 20) & 0x03FF,
(this.PackedValue >> 30) & 0x03) / Multiplier;
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgba32(Rgba32 source) public void PackFromArgb32(Argb32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromArgb32(Argb32 source) public void PackFromBgr24(Bgr24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromBgra32(Bgra32 source) public void PackFromBgra32(Bgra32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
this.PackFromVector4(source.ToVector4());
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb24(ref Rgb24 dest) public void PackFromGray8(Gray8 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc /> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgba32(ref Rgba32 dest) public void PackFromGray16(Gray16 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToArgb32(ref Argb32 dest) public void PackFromRgb24(Rgb24 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgr24(ref Bgr24 dest) public void PackFromRgba32(Rgba32 source) => this.PackFromScaledVector4(source.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToBgra32(ref Bgra32 dest) public Rgba32 ToRgba32() => new Rgba32(this.ToScaledVector4());
{
Vector4 vector = this.ToVector4() * 255F;
dest.R = (byte)MathF.Round(vector.X);
dest.G = (byte)MathF.Round(vector.Y);
dest.B = (byte)MathF.Round(vector.Z);
dest.A = (byte)MathF.Round(vector.W);
}
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgb48(Rgb48 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public void ToRgb48(ref Rgb48 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4()); public void PackFromRgba64(Rgba64 source) => this.PackFromScaledVector4(source.ToScaledVector4());
/// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4());
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj) => obj is Rgba1010102 other && this.Equals(other);
{
return obj is Rgba1010102 other && this.Equals(other);
}
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public bool Equals(Rgba1010102 other) public bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue;
{
return this.PackedValue == other.PackedValue;
}
/// <inheritdoc /> /// <inheritdoc />
public override string ToString() public override string ToString()
{ {
return this.ToVector4().ToString(); var vector = this.ToVector4();
return FormattableString.Invariant($"Rgba1010102({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})");
} }
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(InliningOptions.ShortMethod)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <summary> [MethodImpl(InliningOptions.ShortMethod)]
/// Packs the <see cref="float"/> components into a <see cref="uint"/>. private static uint Pack(ref Vector4 vector)
/// </summary>
/// <param name="x">The x-component</param>
/// <param name="y">The y-component</param>
/// <param name="z">The z-component</param>
/// <param name="w">The w-component</param>
/// <returns>The <see cref="uint"/> containing the packed values.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static uint Pack(float x, float y, float z, float w)
{ {
vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier;
return (uint)( return (uint)(
(((int)Math.Round(x.Clamp(0, 1) * 1023F) & 0x03FF) << 0) | (((int)Math.Round(vector.X) & 0x03FF) << 0)
(((int)Math.Round(y.Clamp(0, 1) * 1023F) & 0x03FF) << 10) | | (((int)Math.Round(vector.Y) & 0x03FF) << 10)
(((int)Math.Round(z.Clamp(0, 1) * 1023F) & 0x03FF) << 20) | | (((int)Math.Round(vector.Z) & 0x03FF) << 20)
(((int)Math.Round(w.Clamp(0, 1) * 3F) & 0x03) << 30)); | (((int)Math.Round(vector.W) & 0x03) << 30));
} }
} }
} }

160
src/ImageSharp/PixelFormats/Rgba32.PixelOperations.cs

@ -3,7 +3,6 @@
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices; using System.Runtime.InteropServices;
using SixLabors.Memory; using SixLabors.Memory;
@ -19,100 +18,18 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
internal partial class PixelOperations : PixelOperations<Rgba32> internal partial class PixelOperations : PixelOperations<Rgba32>
{ {
/// <summary>
/// SIMD optimized bulk implementation of <see cref="IPixel.PackFromVector4(Vector4)"/>
/// that works only with `count` divisible by <see cref="Vector{UInt32}.Count"/>.
/// </summary>
/// <param name="sourceColors">The <see cref="Span{T}"/> to the source colors.</param>
/// <param name="destVectors">The <see cref="Span{T}"/> to the dstination vectors.</param>
/// <param name="count">The number of pixels to convert.</param>
/// <remarks>
/// Implementation adapted from:
/// <see>
/// <cref>http://stackoverflow.com/a/5362789</cref>
/// </see>
/// TODO: We can replace this implementation in the future using new Vector API-s:
/// <see>
/// <cref>https://github.com/dotnet/corefx/issues/15957</cref>
/// </see>
/// </remarks>
internal static void ToVector4SimdAligned(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destVectors, int count)
{
if (!Vector.IsHardwareAccelerated)
{
throw new InvalidOperationException(
"Rgba32.PixelOperations.ToVector4SimdAligned() should not be called when Vector.IsHardwareAccelerated == false!");
}
DebugGuard.IsTrue(
count % Vector<uint>.Count == 0,
nameof(count),
"Argument 'count' should divisible by Vector<uint>.Count!");
var bVec = new Vector<float>(256.0f / 255.0f);
var magicFloat = new Vector<float>(32768.0f);
var magicInt = new Vector<uint>(1191182336); // reinterpreded value of 32768.0f
var mask = new Vector<uint>(255);
int unpackedRawCount = count * 4;
ref uint sourceBase = ref Unsafe.As<Rgba32, uint>(ref MemoryMarshal.GetReference(sourceColors));
ref UnpackedRGBA destBaseAsUnpacked = ref Unsafe.As<Vector4, UnpackedRGBA>(ref MemoryMarshal.GetReference(destVectors));
ref Vector<uint> destBaseAsUInt = ref Unsafe.As<UnpackedRGBA, Vector<uint>>(ref destBaseAsUnpacked);
ref Vector<float> destBaseAsFloat = ref Unsafe.As<UnpackedRGBA, Vector<float>>(ref destBaseAsUnpacked);
for (int i = 0; i < count; i++)
{
uint sVal = Unsafe.Add(ref sourceBase, i);
ref UnpackedRGBA dst = ref Unsafe.Add(ref destBaseAsUnpacked, i);
// This call is the bottleneck now:
dst.Load(sVal);
}
int numOfVectors = unpackedRawCount / Vector<uint>.Count;
for (int i = 0; i < numOfVectors; i++)
{
Vector<uint> vi = Unsafe.Add(ref destBaseAsUInt, i);
vi &= mask;
vi |= magicInt;
var vf = Vector.AsVectorSingle(vi);
vf = (vf - magicFloat) * bVec;
Unsafe.Add(ref destBaseAsFloat, i) = vf;
}
}
/// <inheritdoc /> /// <inheritdoc />
internal override void ToVector4(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destinationVectors, int count) internal override void ToVector4(ReadOnlySpan<Rgba32> sourceColors, Span<Vector4> destinationVectors, int count)
{ {
Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors)); Guard.MustBeSizedAtLeast(sourceColors, count, nameof(sourceColors));
Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors)); Guard.MustBeSizedAtLeast(destinationVectors, count, nameof(destinationVectors));
if (count < 256 || !Vector.IsHardwareAccelerated) sourceColors = sourceColors.Slice(0, count);
{ destinationVectors = destinationVectors.Slice(0, count);
// Doesn't worth to bother with SIMD:
base.ToVector4(sourceColors, destinationVectors, count);
return;
}
int remainder = count % Vector<uint>.Count; SimdUtils.BulkConvertByteToNormalizedFloat(
int alignedCount = count - remainder; MemoryMarshal.Cast<Rgba32, byte>(sourceColors),
MemoryMarshal.Cast<Vector4, float>(destinationVectors));
if (alignedCount > 0)
{
ToVector4SimdAligned(sourceColors, destinationVectors, alignedCount);
}
if (remainder > 0)
{
sourceColors = sourceColors.Slice(alignedCount);
destinationVectors = destinationVectors.Slice(alignedCount);
base.ToVector4(sourceColors, destinationVectors, remainder);
}
} }
/// <inheritdoc /> /// <inheritdoc />
@ -120,29 +37,12 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count); GuardSpans(sourceVectors, nameof(sourceVectors), destinationColors, nameof(destinationColors), count);
if (!SimdUtils.IsAvx2CompatibleArchitecture) sourceVectors = sourceVectors.Slice(0, count);
{ destinationColors = destinationColors.Slice(0, count);
base.PackFromVector4(sourceVectors, destinationColors, count);
return;
}
int remainder = count % 2;
int alignedCount = count - remainder;
if (alignedCount > 0)
{
ReadOnlySpan<float> flatSrc = MemoryMarshal.Cast<Vector4, float>(sourceVectors.Slice(0, alignedCount));
Span<byte> flatDest = MemoryMarshal.Cast<Rgba32, byte>(destinationColors);
SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(flatSrc, flatDest); SimdUtils.BulkConvertNormalizedFloatToByteClampOverflows(
} MemoryMarshal.Cast<Vector4, float>(sourceVectors),
MemoryMarshal.Cast<Rgba32, byte>(destinationColors));
if (remainder > 0)
{
// actually: remainder == 1
int lastIdx = count - 1;
destinationColors[lastIdx].PackFromVector4(sourceVectors[lastIdx]);
}
} }
/// <inheritdoc /> /// <inheritdoc />
@ -156,46 +56,6 @@ namespace SixLabors.ImageSharp.PixelFormats
{ {
this.PackFromVector4(sourceVectors, destinationColors, count); this.PackFromVector4(sourceVectors, destinationColors, count);
} }
/// <inheritdoc />
internal override void PackFromRgba32(ReadOnlySpan<Rgba32> source, Span<Rgba32> destPixels, int count)
{
GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count);
source.Slice(0, count).CopyTo(destPixels);
}
/// <inheritdoc />
internal override void ToRgba32(ReadOnlySpan<Rgba32> sourcePixels, Span<Rgba32> dest, int count)
{
GuardSpans(sourcePixels, nameof(sourcePixels), dest, nameof(dest), count);
sourcePixels.Slice(0, count).CopyTo(dest);
}
/// <summary>
/// Value type to store <see cref="Rgba32"/>-s unpacked into multiple <see cref="uint"/>-s.
/// </summary>
[StructLayout(LayoutKind.Sequential)]
private struct UnpackedRGBA
{
private uint r;
private uint g;
private uint b;
private uint a;
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public void Load(uint p)
{
this.r = p;
this.g = p >> GreenShift;
this.b = p >> BlueShift;
this.a = p >> AlphaShift;
}
}
} }
} }
} }

Some files were not shown because too many files changed in this diff

Loading…
Cancel
Save