Browse Source

Merge branch 'master' into feature/adaptiveHistogramEqualization

pull/673/head
Brian Popow 8 years ago
committed by GitHub
parent
commit
d24cfb2ee3
No known key found for this signature in database GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      .travis.yml
  2. 8
      ImageSharp.sln
  3. 7
      README.md
  4. 5
      appveyor.yml
  5. 9
      run-tests.ps1
  6. 2
      src/ImageSharp.Drawing/Processing/BrushApplicator.cs
  7. 85
      src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs
  8. 8
      src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs
  9. 70
      src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs
  10. 16
      src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs
  11. 5
      src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs
  12. 22
      src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs
  13. 2
      src/ImageSharp/Common/Helpers/DebugGuard.cs
  14. 6
      src/ImageSharp/Common/Helpers/Guard.cs
  15. 1
      src/ImageSharp/Formats/Bmp/BmpDecoder.cs
  16. 4
      src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs
  17. 4
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  18. 2
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  19. 4
      src/ImageSharp/Formats/Gif/LzwDecoder.cs
  20. 23
      src/ImageSharp/Formats/ImageFormatManager.cs
  21. 3
      src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs
  22. 9
      src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs
  23. 4
      src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs
  24. 9
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  25. 4
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  26. 2
      src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs
  27. 113
      src/ImageSharp/GraphicsOptions.cs
  28. 2
      src/ImageSharp/Image.Decode.cs
  29. 6
      src/ImageSharp/ImageExtensions.cs
  30. 9
      src/ImageSharp/ImageFrameCollection.cs
  31. 9
      src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs
  32. 5
      src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs
  33. 7
      src/ImageSharp/MetaData/Profiles/Exif/ExifTagDescriptionAttribute.cs
  34. 10
      src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs
  35. 6
      src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs
  36. 4
      src/ImageSharp/MetaData/Profiles/ICC/Curves/IccCurveSegment.cs
  37. 2
      src/ImageSharp/MetaData/Profiles/ICC/Curves/IccOneDimensionalCurve.cs
  38. 2
      src/ImageSharp/MetaData/Profiles/ICC/Curves/IccResponseCurve.cs
  39. 4
      src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs
  40. 2
      src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs
  41. 6
      src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.TagDataEntry.cs
  42. 6
      src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs
  43. 2
      src/ImageSharp/MetaData/Profiles/ICC/IccTagDataEntry.cs
  44. 3
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccClutProcessElement.cs
  45. 3
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs
  46. 2
      src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMultiProcessElement.cs
  47. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs
  48. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs
  49. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs
  50. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs
  51. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs
  52. 5
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs
  53. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs
  54. 5
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs
  55. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLut16TagDataEntry.cs
  56. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLut8TagDataEntry.cs
  57. 10
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLutAToBTagDataEntry.cs
  58. 10
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLutBToATagDataEntry.cs
  59. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMeasurementTagDataEntry.cs
  60. 5
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs
  61. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs
  62. 3
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccProfileSequenceDescTagDataEntry.cs
  63. 3
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccProfileSequenceIdentifierTagDataEntry.cs
  64. 4
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccScreeningTagDataEntry.cs
  65. 5
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccSignatureTagDataEntry.cs
  66. 2
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccTextDescriptionTagDataEntry.cs
  67. 3
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs
  68. 3
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs
  69. 3
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs
  70. 5
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs
  71. 5
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs
  72. 5
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs
  73. 12
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs
  74. 5
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs
  75. 3
      src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccXyzTagDataEntry.cs
  76. 2
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccClut.cs
  77. 4
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccColorantTableEntry.cs
  78. 7
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccLocalizedString.cs
  79. 3
      src/ImageSharp/MetaData/Profiles/ICC/Various/IccLut.cs
  80. 5
      src/ImageSharp/PixelFormats/Alpha8.cs
  81. 7
      src/ImageSharp/PixelFormats/Argb32.cs
  82. 5
      src/ImageSharp/PixelFormats/Bgr565.cs
  83. 10
      src/ImageSharp/PixelFormats/Bgra32.cs
  84. 5
      src/ImageSharp/PixelFormats/Bgra4444.cs
  85. 5
      src/ImageSharp/PixelFormats/Bgra5551.cs
  86. 5
      src/ImageSharp/PixelFormats/Byte4.cs
  87. 2
      src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs
  88. 5
      src/ImageSharp/PixelFormats/HalfSingle.cs
  89. 5
      src/ImageSharp/PixelFormats/HalfVector2.cs
  90. 5
      src/ImageSharp/PixelFormats/HalfVector4.cs
  91. 5
      src/ImageSharp/PixelFormats/NormalizedByte2.cs
  92. 5
      src/ImageSharp/PixelFormats/NormalizedByte4.cs
  93. 63
      src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs
  94. 3561
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs
  95. 48
      src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt
  96. 2600
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs
  97. 298
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt
  98. 449
      src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs
  99. 56
      src/ImageSharp/PixelFormats/PixelColorBlendingMode.cs
  100. 265
      src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs

2
.travis.yml

@ -6,7 +6,7 @@ matrix:
- os: linux # Ubuntu 14.04 - os: linux # Ubuntu 14.04
dist: trusty dist: trusty
sudo: required sudo: required
dotnet: 2.1.300 dotnet: 2.1.401
mono: latest mono: latest
# - os: osx # OSX 10.11 # - os: osx # OSX 10.11
# osx_image: xcode7.3.1 # osx_image: xcode7.3.1

8
ImageSharp.sln

@ -1,7 +1,6 @@
 
Microsoft Visual Studio Solution File, Format Version 12.00 Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio 15 # Visual Studio 15
VisualStudioVersion = 15.0.26730.3
VisualStudioVersion = 15.0.26730.12 VisualStudioVersion = 15.0.26730.12
MinimumVisualStudioVersion = 10.0.40219.1 MinimumVisualStudioVersion = 10.0.40219.1
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionItems", "{C317F1B1-D75E-4C6D-83EB-80367343E0D7}"
@ -19,6 +18,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt
NuGet.config = NuGet.config NuGet.config = NuGet.config
.github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md .github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md
README.md = README.md README.md = README.md
run-tests.ps1 = run-tests.ps1
EndProjectSection EndProjectSection
EndProject EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}" Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Source", "Source", "{815C0625-CD3D-440F-9F80-2D83856AB7AE}"
@ -46,9 +46,6 @@ EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{561B880A-D9EE-44EF-90F5-817C54A9D9AB}" Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp.Sandbox46", "tests\ImageSharp.Sandbox46\ImageSharp.Sandbox46.csproj", "{561B880A-D9EE-44EF-90F5-817C54A9D9AB}"
EndProject EndProject
Global Global
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(SolutionConfigurationPlatforms) = preSolution GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU Debug|Any CPU = Debug|Any CPU
Debug|x64 = Debug|x64 Debug|x64 = Debug|x64
@ -133,4 +130,7 @@ Global
GlobalSection(ExtensibilityGlobals) = postSolution GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795} SolutionGuid = {5F8B9D1F-CD8B-4CC5-8216-D531E25BD795}
EndGlobalSection EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal EndGlobal

7
README.md

@ -117,12 +117,9 @@ For more examples check out:
If you prefer, you can compile ImageSharp yourself (please do and help!) If you prefer, you can compile ImageSharp yourself (please do and help!)
- Using [Visual Studio 2017 Preview](https://docs.microsoft.com/en-us/visualstudio/releasenotes/vs2017-preview-relnotes) - Using [Visual Studio 2017](https://visualstudio.microsoft.com/vs/)
- Make sure you have the latest version installed - Make sure you have the latest version installed
- Make sure you have [the newest 2.1 RC1 SDK installed](https://www.microsoft.com/net/core#windows) - Make sure you have [the .NET Core 2.1 SDK](https://www.microsoft.com/net/core#windows) installed
- Using [Visual Studio 2017](https://www.visualstudio.com/en-us/news/releasenotes/vs2017-relnotes)
- If you are unable and/or don't want to build ImageSharp.Tests against 2.1 RC, remove the `netcoreapp2.1` target [from TargetFrameworks](https://github.com/SixLabors/ImageSharp/blob/master/tests/ImageSharp.Tests/ImageSharp.Tests.csproj#L3) locally
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**:

5
appveyor.yml

@ -12,9 +12,6 @@ environment:
- target_framework: netcoreapp2.1 - target_framework: netcoreapp2.1
is_32bit: True is_32bit: True
- target_framework: netcoreapp2.0
is_32bit: False
- target_framework: net471 - target_framework: net471
is_32bit: False is_32bit: False
@ -27,8 +24,6 @@ environment:
- target_framework: net462 - target_framework: net462
is_32bit: True is_32bit: True
#- target_framework: netcoreapp2.0 # As far as I understand, 32 bit test execution is not supported by "dotnet xunit"
# is_32bit: True
#- target_framework: mono #- target_framework: mono
# is_32bit: False # is_32bit: False
#- target_framework: mono #- target_framework: mono

9
run-tests.ps1

@ -41,8 +41,8 @@ function CheckSubmoduleStatus() {
} }
if ( ($targetFramework -eq "netcoreapp2.0") -and ($env:CI -eq "True") -and ($is32Bit -ne "True")) { if ( ($targetFramework -eq "netcoreapp2.1") -and ($env:CI -eq "True") -and ($is32Bit -ne "True")) {
# We execute CodeCoverage.cmd only for one specific job on CI (netcoreapp2.0 + 64bit ) # We execute CodeCoverage.cmd only for one specific job on CI (netcoreapp2.1 + 64bit )
$testRunnerCmd = ".\tests\CodeCoverage\CodeCoverage.cmd" $testRunnerCmd = ".\tests\CodeCoverage\CodeCoverage.cmd"
} }
elseif ($targetFramework -eq "mono") { elseif ($targetFramework -eq "mono") {
@ -70,11 +70,6 @@ else {
cd .\tests\ImageSharp.Tests cd .\tests\ImageSharp.Tests
$xunitArgs = "-nobuild -c Release -framework $targetFramework" $xunitArgs = "-nobuild -c Release -framework $targetFramework"
if ($targetFramework -eq "netcoreapp2.0") {
# There were issues matching the correct installed runtime if we do not specify it explicitly:
$xunitArgs += " --fx-version 2.0.0"
}
if ($targetFramework -eq "netcoreapp2.1") { if ($targetFramework -eq "netcoreapp2.1") {
# There were issues matching the correct installed runtime if we do not specify it explicitly: # There were issues matching the correct installed runtime if we do not specify it explicitly:
$xunitArgs += " --fx-version 2.1.0" $xunitArgs += " --fx-version 2.1.0"

2
src/ImageSharp.Drawing/Processing/BrushApplicator.cs

@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.Processing
{ {
this.Target = target; this.Target = target;
this.Options = options; this.Options = options;
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options.BlenderMode); this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(options);
} }
/// <summary> /// <summary>

85
src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float opacity) public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float opacity)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, opacity)); => source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, Point.Empty, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity));
/// <summary> /// <summary>
/// Draws the given image together with the current one by blending their pixels. /// Draws the given image together with the current one by blending their pixels.
@ -30,63 +30,92 @@ namespace SixLabors.ImageSharp.Processing
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param> /// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="blender">The blending mode.</param> /// <param name="colorBlending">The blending mode.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float opacity) public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelColorBlendingMode colorBlending, float opacity)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, opacity, blender)); => source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, Point.Empty, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity));
/// <summary> /// <summary>
/// Draws the given image together with the current one by blending their pixels. /// Draws the given image together with the current one by blending their pixels.
/// </summary> /// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param> /// <param name="source">The image this method extends.</param>
/// <param name="options">The options, including the blending type and blending amount.</param>
/// <param name="image">The image to blend with the currently processing image.</param> /// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="colorBlending">The color blending mode.</param>
/// <param name="alphaComposition">The alpha composition mode.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, Image<TPixel> image) public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, options)); => source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, Point.Empty, colorBlending, alphaComposition, opacity));
/// <summary> /// <summary>
/// Draws the given image together with the current one by blending their pixels. /// Draws the given image together with the current one by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param> /// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="options">The options, including the blending type and blending amount.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, Point.Empty, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage));
/// <summary>
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param> /// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param> /// <param name="location">The location to draw the blended image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, float opacity, Point location) public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, Point location, float opacity)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, opacity)); => source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity));
/// <summary> /// <summary>
/// Draws the given image together with the current one by blending their pixels. /// Draws the given image together with the current one by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="blender">The type of bending to apply.</param> /// <param name="source">The image this method extends.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param> /// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param> /// <param name="location">The location to draw the blended image.</param>
/// <param name="colorBlending">The color blending to apply.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, PixelBlenderMode blender, float opacity, Point location) public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, Point location, PixelColorBlendingMode colorBlending, float opacity)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, opacity, blender)); => source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity));
/// <summary> /// <summary>
/// Draws the given image together with the current one by blending their pixels. /// Draws the given image together with the current one by blending their pixels.
/// </summary> /// </summary>
/// <param name="source">The image this method extends.</param>
/// <param name="options">The options containing the blend mode and opacity.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param> /// <param name="location">The location to draw the blended image.</param>
/// <param name="colorBlending">The color blending to apply.</param>
/// <param name="alphaComposition">The alpha composition mode.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, Point location, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity)
where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, colorBlending, alphaComposition, opacity));
/// <summary>
/// Draws the given image together with the current one by blending their pixels.
/// </summary>
/// <typeparam name="TPixel">The pixel format.</typeparam>
/// <param name="source">The image this method extends.</param>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="options">The options containing the blend mode and opacity.</param>
/// <returns>The <see cref="Image{TPixel}"/>.</returns> /// <returns>The <see cref="Image{TPixel}"/>.</returns>
public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, GraphicsOptions options, Image<TPixel> image, Point location) public static IImageProcessingContext<TPixel> DrawImage<TPixel>(this IImageProcessingContext<TPixel> source, Image<TPixel> image, Point location, GraphicsOptions options)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
=> source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, options)); => source.ApplyProcessor(new DrawImageProcessor<TPixel>(image, location, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage));
} }
} }

8
src/ImageSharp.Drawing/Processing/GradientBrushBase{TPixel}.cs

@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.Processing
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
} }
var (from, to) = this.GetGradientSegment(positionOnCompleteGradient); (ColorStop<TPixel> from, ColorStop<TPixel> to) = this.GetGradientSegment(positionOnCompleteGradient);
if (from.Color.Equals(to.Color)) if (from.Color.Equals(to.Color))
{ {
@ -124,7 +124,7 @@ namespace SixLabors.ImageSharp.Processing
float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / to.Ratio; float onLocalGradient = (positionOnCompleteGradient - from.Ratio) / to.Ratio;
// TODO: this should be changeble for different gradienting functions // TODO: this should be changeble for different gradienting functions
Vector4 result = PorterDuffFunctions.Normal( Vector4 result = PorterDuffFunctions.NormalSrcOver(
fromAsVector, fromAsVector,
toAsVector, toAsVector,
onLocalGradient); onLocalGradient);
@ -153,11 +153,11 @@ namespace SixLabors.ImageSharp.Processing
private (ColorStop<TPixel> from, ColorStop<TPixel> to) GetGradientSegment( private (ColorStop<TPixel> from, ColorStop<TPixel> to) GetGradientSegment(
float positionOnCompleteGradient) float positionOnCompleteGradient)
{ {
var localGradientFrom = this.colorStops[0]; ColorStop<TPixel> localGradientFrom = this.colorStops[0];
ColorStop<TPixel> localGradientTo = default; ColorStop<TPixel> localGradientTo = default;
// TODO: ensure colorStops has at least 2 items (technically 1 would be okay, but that's no gradient) // TODO: ensure colorStops has at least 2 items (technically 1 would be okay, but that's no gradient)
foreach (var colorStop in this.colorStops) foreach (ColorStop<TPixel> colorStop in this.colorStops)
{ {
localGradientTo = colorStop; localGradientTo = colorStop;

70
src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs

@ -18,80 +18,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
/// <typeparam name="TPixel">The pixel format.</typeparam> /// <typeparam name="TPixel">The pixel format.</typeparam>
internal class DrawImageProcessor<TPixel> : ImageProcessor<TPixel> internal class DrawImageProcessor<TPixel> : ImageProcessor<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class. /// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary> /// </summary>
/// <param name="image">The image to blend with the currently processing image.</param> /// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="colorBlendingMode">The blending mode to use when drawing the image.</param>
/// <param name="alphaCompositionMode">The Alpha blending mode to use when drawing the image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param> /// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
public DrawImageProcessor(Image<TPixel> image, float opacity) public DrawImageProcessor(Image<TPixel> image, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity)
: this(image, Point.Empty, opacity)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="options">
/// The options containing the opacity of the image to blend and blending mode.
/// Opacity must be between 0 and 1.
/// </param>
public DrawImageProcessor(Image<TPixel> image, GraphicsOptions options)
: this(image, Point.Empty, options)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
public DrawImageProcessor(Image<TPixel> image, Point location, float opacity)
: this(image, location, opacity, GraphicsOptions.Default.BlenderMode)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="options">
/// The options containing the opacity of the image to blend and blending mode.
/// Opacity must be between 0 and 1.
/// </param>
public DrawImageProcessor(Image<TPixel> image, Point location, GraphicsOptions options)
: this(image, location, options.BlendPercentage, options.BlenderMode)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <param name="blenderMode">The blending mode to use when drawing the image.</param>
public DrawImageProcessor(Image<TPixel> image, float opacity, PixelBlenderMode blenderMode)
: this(image, Point.Empty, opacity, blenderMode)
{
}
/// <summary>
/// Initializes a new instance of the <see cref="DrawImageProcessor{TPixel}"/> class.
/// </summary>
/// <param name="image">The image to blend with the currently processing image.</param>
/// <param name="location">The location to draw the blended image.</param>
/// <param name="opacity">The opacity of the image to blend. Must be between 0 and 1.</param>
/// <param name="blenderMode">The blending mode to use when drawing the image.</param>
public DrawImageProcessor(Image<TPixel> image, Point location, float opacity, PixelBlenderMode blenderMode)
{ {
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.Image = image; this.Image = image;
this.Opacity = opacity; this.Opacity = opacity;
this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(blenderMode); this.Blender = PixelOperations<TPixel>.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode);
this.Location = location; this.Location = location;
} }

16
src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs

@ -102,14 +102,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing
private bool IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush) private bool IsSolidBrushWithoutBlending(out SolidBrush<TPixel> solidBrush)
{ {
solidBrush = this.brush as SolidBrush<TPixel>; solidBrush = this.brush as SolidBrush<TPixel>;
return solidBrush != null if (solidBrush == null)
&& ((this.options.BlenderMode == PixelBlenderMode.Normal && this.options.BlendPercentage == 1f {
&& solidBrush.Color.ToVector4().W == 1f) return false;
|| (this.options.BlenderMode == PixelBlenderMode.Over && this.options.BlendPercentage == 1f }
&& solidBrush.Color.ToVector4().W == 1f)
|| (this.options.BlenderMode == PixelBlenderMode.Src)); return this.options.IsOpaqueColorWithoutBlending(solidBrush.Color);
} }
} }
} }

5
src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs

@ -37,9 +37,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text
{ {
Guard.NotNull(text, nameof(text)); Guard.NotNull(text, nameof(text));
Guard.NotNull(font, nameof(font)); Guard.NotNull(font, nameof(font));
if (brush == null && pen == null)
if (brush is null && pen is null)
{ {
throw new ArgumentNullException($"at least one of {nameof(brush)} or {nameof(pen)} must not be null"); throw new ArgumentNullException($"Expected a {nameof(brush)} or {nameof(pen)}. Both were null");
} }
this.Options = options; this.Options = options;

22
src/ImageSharp.Drawing/Processing/TextGraphicsOptions.cs

@ -32,7 +32,9 @@ namespace SixLabors.ImageSharp.Processing
private float? dpiY; private float? dpiY;
private PixelBlenderMode blenderMode; private PixelColorBlendingMode colorBlendingMode;
private PixelAlphaCompositionMode alphaCompositionMode;
private float wrapTextWidth; private float wrapTextWidth;
@ -53,7 +55,8 @@ namespace SixLabors.ImageSharp.Processing
this.verticalAlignment = VerticalAlignment.Top; this.verticalAlignment = VerticalAlignment.Top;
this.antialiasSubpixelDepth = 16; this.antialiasSubpixelDepth = 16;
this.blenderMode = PixelBlenderMode.Normal; this.colorBlendingMode = PixelColorBlendingMode.Normal;
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver;
this.blendPercentage = 1; this.blendPercentage = 1;
this.antialias = enableAntialiasing; this.antialias = enableAntialiasing;
this.dpiX = DefaultTextDpi; this.dpiX = DefaultTextDpi;
@ -80,9 +83,14 @@ namespace SixLabors.ImageSharp.Processing
// some API thought post V1. // some API thought post V1.
/// <summary> /// <summary>
/// Gets or sets a value indicating the blending percentage to apply to the drawing operation /// Gets or sets a value indicating the color blending percentage to apply to the drawing operation
/// </summary>
public PixelColorBlendingMode ColorBlendingMode { get => this.colorBlendingMode; set => this.colorBlendingMode = value; }
/// <summary>
/// Gets or sets a value indicating the color blending percentage to apply to the drawing operation
/// </summary> /// </summary>
public PixelBlenderMode BlenderMode { get => this.blenderMode; set => this.blenderMode = value; } public PixelAlphaCompositionMode AlphaCompositionMode { get => this.alphaCompositionMode; set => this.alphaCompositionMode = value; }
/// <summary> /// <summary>
/// Gets or sets a value indicating whether the text should be drawing with kerning enabled. /// Gets or sets a value indicating whether the text should be drawing with kerning enabled.
@ -135,7 +143,8 @@ namespace SixLabors.ImageSharp.Processing
{ {
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, AntialiasSubpixelDepth = options.AntialiasSubpixelDepth,
blendPercentage = options.BlendPercentage, blendPercentage = options.BlendPercentage,
blenderMode = options.BlenderMode colorBlendingMode = options.ColorBlendingMode,
alphaCompositionMode = options.AlphaCompositionMode
}; };
} }
@ -151,7 +160,8 @@ namespace SixLabors.ImageSharp.Processing
return new GraphicsOptions(options.Antialias) return new GraphicsOptions(options.Antialias)
{ {
AntialiasSubpixelDepth = options.AntialiasSubpixelDepth, AntialiasSubpixelDepth = options.AntialiasSubpixelDepth,
BlenderMode = options.BlenderMode, ColorBlendingMode = options.ColorBlendingMode,
AlphaCompositionMode = options.AlphaCompositionMode,
BlendPercentage = options.BlendPercentage BlendPercentage = options.BlendPercentage
}; };
} }

2
src/ImageSharp/Common/Helpers/DebugGuard.cs

@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp
public static void NotNull<T>(T value, string parameterName) public static void NotNull<T>(T value, string parameterName)
where T : class where T : class
{ {
if (value == null) if (value is null)
{ {
throw new ArgumentNullException(parameterName); throw new ArgumentNullException(parameterName);
} }

6
src/ImageSharp/Common/Helpers/Guard.cs

@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp
public static void NotNull<T>(T value, string parameterName) public static void NotNull<T>(T value, string parameterName)
where T : class where T : class
{ {
if (value == null) if (value is null)
{ {
throw new ArgumentNullException(parameterName); throw new ArgumentNullException(parameterName);
} }
@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp
/// <exception cref="ArgumentException"><paramref name="value"/> is empty or contains only blanks.</exception> /// <exception cref="ArgumentException"><paramref name="value"/> is empty or contains only blanks.</exception>
public static void NotNullOrWhiteSpace(string value, string parameterName) public static void NotNullOrWhiteSpace(string value, string parameterName)
{ {
if (value == null) if (value is null)
{ {
throw new ArgumentNullException(parameterName); throw new ArgumentNullException(parameterName);
} }
@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp
/// <exception cref="ArgumentException"><paramref name="value"/> is empty.</exception> /// <exception cref="ArgumentException"><paramref name="value"/> is empty.</exception>
public static void NotNullOrEmpty<T>(ICollection<T> value, string parameterName) public static void NotNullOrEmpty<T>(ICollection<T> value, string parameterName)
{ {
if (value == null) if (value is null)
{ {
throw new ArgumentNullException(parameterName); throw new ArgumentNullException(parameterName);
} }

1
src/ImageSharp/Formats/Bmp/BmpDecoder.cs

@ -25,7 +25,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp
{ {
/// <inheritdoc/> /// <inheritdoc/>
public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream) public Image<TPixel> Decode<TPixel>(Configuration configuration, Stream stream)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
Guard.NotNull(stream, nameof(stream)); Guard.NotNull(stream, nameof(stream));

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

@ -373,11 +373,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp
for (int x = 0; x < arrayWidth; x++) for (int x = 0; x < arrayWidth; x++)
{ {
int colOffset = x * ppb; int colOffset = x * ppb;
for (int shift = 0, newX = colOffset; shift < ppb && newX < width; shift++, newX++)
for (int shift = 0; shift < ppb && (x + shift) < width; shift++)
{ {
int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4; int colorIndex = ((rowSpan[offset] >> (8 - bits - (shift * bits))) & mask) * 4;
int newX = colOffset + shift;
// Stored in b-> g-> r order. // Stored in b-> g-> r order.
rgba.Bgr = Unsafe.As<byte, Bgr24>(ref colors[colorIndex]); rgba.Bgr = Unsafe.As<byte, Bgr24>(ref colors[colorIndex]);

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

@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
ImageFrame<TPixel> currentFrame = null; ImageFrame<TPixel> currentFrame = null;
ImageFrame<TPixel> imageFrame; ImageFrame<TPixel> imageFrame;
if (previousFrame == null) if (previousFrame is null)
{ {
// This initializes the image to become fully transparent because the alpha channel is zero. // This initializes the image to become fully transparent because the alpha channel is zero.
image = new Image<TPixel>(this.configuration, imageWidth, imageHeight, this.metaData); image = new Image<TPixel>(this.configuration, imageWidth, imageHeight, this.metaData);
@ -485,7 +485,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
private void RestoreToBackground<TPixel>(ImageFrame<TPixel> frame) private void RestoreToBackground<TPixel>(ImageFrame<TPixel> frame)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
if (this.restoreArea == null) if (this.restoreArea is null)
{ {
return; return;
} }

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

@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
{ {
foreach (ImageFrame<TPixel> frame in image.Frames) foreach (ImageFrame<TPixel> frame in image.Frames)
{ {
if (quantized == null) if (quantized is null)
{ {
quantized = this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(frame); quantized = this.quantizer.CreateFrameQuantizer<TPixel>().QuantizeFrame(frame);
} }

4
src/ImageSharp/Formats/Gif/LzwDecoder.cs

@ -56,9 +56,7 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <exception cref="System.ArgumentNullException"><paramref name="stream"/> is null.</exception> /// <exception cref="System.ArgumentNullException"><paramref name="stream"/> is null.</exception>
public LzwDecoder(MemoryAllocator memoryAllocator, Stream stream) public LzwDecoder(MemoryAllocator memoryAllocator, Stream stream)
{ {
Guard.NotNull(stream, nameof(stream)); this.stream = stream ?? throw new ArgumentNullException(nameof(stream));
this.stream = stream;
this.prefix = memoryAllocator.Allocate<int>(MaxStackSize, AllocationOptions.Clean); this.prefix = memoryAllocator.Allocate<int>(MaxStackSize, AllocationOptions.Clean);
this.suffix = memoryAllocator.Allocate<int>(MaxStackSize, AllocationOptions.Clean); this.suffix = memoryAllocator.Allocate<int>(MaxStackSize, AllocationOptions.Clean);

23
src/ImageSharp/Formats/ImageFormatManager.cs

@ -13,6 +13,12 @@ namespace SixLabors.ImageSharp.Formats
/// </summary> /// </summary>
public class ImageFormatManager public class ImageFormatManager
{ {
/// <summary>
/// Used for locking against as there is no ConcurrentSet type.
/// <see href="https://github.com/dotnet/corefx/issues/6318"/>
/// </summary>
private static readonly object HashLock = new object();
/// <summary> /// <summary>
/// The list of supported <see cref="IImageEncoder"/> keyed to mime types. /// The list of supported <see cref="IImageEncoder"/> keyed to mime types.
/// </summary> /// </summary>
@ -26,7 +32,7 @@ namespace SixLabors.ImageSharp.Formats
/// <summary> /// <summary>
/// The list of supported <see cref="IImageFormat"/>s. /// The list of supported <see cref="IImageFormat"/>s.
/// </summary> /// </summary>
private readonly ConcurrentBag<IImageFormat> imageFormats = new ConcurrentBag<IImageFormat>(); private readonly HashSet<IImageFormat> imageFormats = new HashSet<IImageFormat>();
/// <summary> /// <summary>
/// The list of supported <see cref="IImageFormatDetector"/>s. /// The list of supported <see cref="IImageFormatDetector"/>s.
@ -74,7 +80,14 @@ namespace SixLabors.ImageSharp.Formats
Guard.NotNull(format, nameof(format)); Guard.NotNull(format, nameof(format));
Guard.NotNull(format.MimeTypes, nameof(format.MimeTypes)); Guard.NotNull(format.MimeTypes, nameof(format.MimeTypes));
Guard.NotNull(format.FileExtensions, nameof(format.FileExtensions)); Guard.NotNull(format.FileExtensions, nameof(format.FileExtensions));
this.imageFormats.Add(format);
lock (HashLock)
{
if (!this.imageFormats.Contains(format))
{
this.imageFormats.Add(format);
}
}
} }
/// <summary> /// <summary>
@ -86,9 +99,9 @@ namespace SixLabors.ImageSharp.Formats
{ {
Guard.NotNullOrWhiteSpace(extension, nameof(extension)); Guard.NotNullOrWhiteSpace(extension, nameof(extension));
if (extension[0] == '.') if (extension[0] == '.')
{ {
extension = extension.Substring(1); extension = extension.Substring(1);
} }
return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase)); return this.imageFormats.FirstOrDefault(x => x.FileExtensions.Contains(extension, StringComparer.OrdinalIgnoreCase));

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

@ -44,7 +44,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters
public static JpegColorConverter GetConverter(JpegColorSpace colorSpace) public static JpegColorConverter GetConverter(JpegColorSpace colorSpace)
{ {
JpegColorConverter converter = Converters.FirstOrDefault(c => c.ColorSpace == colorSpace); JpegColorConverter converter = Converters.FirstOrDefault(c => c.ColorSpace == colorSpace);
if (converter == null)
if (converter is null)
{ {
throw new Exception($"Could not find any converter for JpegColorSpace {colorSpace}!"); throw new Exception($"Could not find any converter for JpegColorSpace {colorSpace}!");
} }

9
src/ImageSharp/Formats/Jpeg/Components/GenericBlock8x8.cs

@ -58,13 +58,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components
public void LoadAndStretchEdges<TPixel>(IPixelSource<TPixel> source, int sourceX, int sourceY) public void LoadAndStretchEdges<TPixel>(IPixelSource<TPixel> source, int sourceX, int sourceY)
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
var buffer = source.PixelBuffer as Buffer2D<T>; if (source.PixelBuffer is Buffer2D<T> buffer)
if (buffer == null) {
this.LoadAndStretchEdges(buffer, sourceX, sourceY);
}
else
{ {
throw new InvalidOperationException("LoadAndStretchEdges<TPixels>() is only valid for TPixel == T !"); throw new InvalidOperationException("LoadAndStretchEdges<TPixels>() is only valid for TPixel == T !");
} }
this.LoadAndStretchEdges(buffer, sourceX, sourceY);
} }
/// <summary> /// <summary>

4
src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs

@ -538,7 +538,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
if (ProfileResolver.IsProfile(profile, ProfileResolver.ExifMarker)) if (ProfileResolver.IsProfile(profile, ProfileResolver.ExifMarker))
{ {
this.isExif = true; this.isExif = true;
if (this.exifData == null) if (this.exifData is null)
{ {
// The first 6 bytes (Exif00) will be skipped, because this is Jpeg specific // The first 6 bytes (Exif00) will be skipped, because this is Jpeg specific
this.exifData = profile.Skip(Exif00).ToArray(); this.exifData = profile.Skip(Exif00).ToArray();
@ -575,7 +575,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
byte[] profile = new byte[remaining]; byte[] profile = new byte[remaining];
this.InputStream.Read(profile, 0, remaining); this.InputStream.Read(profile, 0, remaining);
if (this.iccData == null) if (this.iccData is null)
{ {
this.iccData = profile; this.iccData = profile;
} }

9
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -550,7 +550,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
private void WriteDefineHuffmanTables(int componentCount) private void WriteDefineHuffmanTables(int componentCount)
{ {
// Table identifiers. // Table identifiers.
byte[] headers = { 0x00, 0x10, 0x01, 0x11 }; Span<byte> headers = stackalloc byte[] { 0x00, 0x10, 0x01, 0x11 };
int markerlen = 2; int markerlen = 2;
HuffmanSpec[] specs = HuffmanSpec.TheHuffmanSpecs; HuffmanSpec[] specs = HuffmanSpec.TheHuffmanSpecs;
@ -628,7 +629,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
byte[] data = exifProfile?.ToByteArray(); byte[] data = exifProfile?.ToByteArray();
if (data == null || data.Length == 0) if (data is null || data.Length == 0)
{ {
return; return;
} }
@ -687,7 +688,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// </exception> /// </exception>
private void WriteIccProfile(IccProfile iccProfile) private void WriteIccProfile(IccProfile iccProfile)
{ {
if (iccProfile == null) if (iccProfile is null)
{ {
return; return;
} }
@ -698,7 +699,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
byte[] data = iccProfile.ToByteArray(); byte[] data = iccProfile.ToByteArray();
if (data == null || data.Length == 0) if (data is null || data.Length == 0)
{ {
return; return;
} }

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

@ -239,7 +239,7 @@ namespace SixLabors.ImageSharp.Formats.Png
this.ReadPhysicalChunk(metadata, chunk.Data.GetSpan()); this.ReadPhysicalChunk(metadata, chunk.Data.GetSpan());
break; break;
case PngChunkType.Data: case PngChunkType.Data:
if (image == null) if (image is null)
{ {
this.InitializeImage(metadata, out image); this.InitializeImage(metadata, out image);
} }
@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.Formats.Png
} }
} }
if (image == null) if (image is null)
{ {
throw new ImageFormatException("PNG Image does not contain a data chunk"); throw new ImageFormatException("PNG Image does not contain a data chunk");
} }

2
src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs

@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib
public void AllocateNewBytes(int bytes) public void AllocateNewBytes(int bytes)
{ {
this.currentDataRemaining = bytes; this.currentDataRemaining = bytes;
if (this.compressedStream == null) if (this.compressedStream is null)
{ {
this.InitializeInflateStream(); this.InitializeInflateStream();
} }

113
src/ImageSharp/GraphicsOptions.cs

@ -21,7 +21,9 @@ namespace SixLabors.ImageSharp
private bool? antialias; private bool? antialias;
private PixelBlenderMode blenderMode; private PixelColorBlendingMode colorBlendingMode;
private PixelAlphaCompositionMode alphaCompositionMode;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct. /// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
@ -29,10 +31,62 @@ namespace SixLabors.ImageSharp
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param> /// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
public GraphicsOptions(bool enableAntialiasing) public GraphicsOptions(bool enableAntialiasing)
{ {
this.blenderMode = PixelBlenderMode.Normal; this.colorBlendingMode = PixelColorBlendingMode.Normal;
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver;
this.blendPercentage = 1; this.blendPercentage = 1;
this.antialiasSubpixelDepth = 16; this.antialiasSubpixelDepth = 16;
this.antialias = enableAntialiasing; this.antialias = enableAntialiasing;
}
/// <summary>
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
/// </summary>
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
/// <param name="opacity">blending percentage to apply to the drawing operation</param>
public GraphicsOptions(bool enableAntialiasing, float opacity)
{
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.colorBlendingMode = PixelColorBlendingMode.Normal;
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver;
this.blendPercentage = opacity;
this.antialiasSubpixelDepth = 16;
this.antialias = enableAntialiasing;
}
/// <summary>
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
/// </summary>
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
/// <param name="opacity">blending percentage to apply to the drawing operation</param>
/// <param name="blending">color blending mode to apply to the drawing operation</param>
public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, float opacity)
{
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.colorBlendingMode = blending;
this.alphaCompositionMode = PixelAlphaCompositionMode.SrcOver;
this.blendPercentage = opacity;
this.antialiasSubpixelDepth = 16;
this.antialias = enableAntialiasing;
}
/// <summary>
/// Initializes a new instance of the <see cref="GraphicsOptions"/> struct.
/// </summary>
/// <param name="enableAntialiasing">If set to <c>true</c> [enable antialiasing].</param>
/// <param name="opacity">blending percentage to apply to the drawing operation</param>
/// <param name="blending">color blending mode to apply to the drawing operation</param>
/// <param name="composition">alpha composition mode to apply to the drawing operation</param>
public GraphicsOptions(bool enableAntialiasing, PixelColorBlendingMode blending, PixelAlphaCompositionMode composition, float opacity)
{
Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity));
this.colorBlendingMode = blending;
this.alphaCompositionMode = composition;
this.blendPercentage = opacity;
this.antialiasSubpixelDepth = 16;
this.antialias = enableAntialiasing;
} }
/// <summary> /// <summary>
@ -67,12 +121,59 @@ namespace SixLabors.ImageSharp
// some API thought post V1. // some API thought post V1.
/// <summary> /// <summary>
/// Gets or sets a value indicating the blending mode to apply to the drawing operation /// Gets or sets a value indicating the color blending mode to apply to the drawing operation
/// </summary>
public PixelColorBlendingMode ColorBlendingMode
{
get => this.colorBlendingMode;
set => this.colorBlendingMode = value;
}
/// <summary>
/// Gets or sets a value indicating the alpha composition mode to apply to the drawing operation
/// </summary> /// </summary>
public PixelBlenderMode BlenderMode public PixelAlphaCompositionMode AlphaCompositionMode
{ {
get => this.blenderMode; get => this.alphaCompositionMode;
set => this.blenderMode = value; set => this.alphaCompositionMode = value;
}
/// <summary>
/// Evaluates if a given SOURCE color can completely replace a BACKDROP color given the current blending and composition settings.
/// </summary>
/// <typeparam name="TPixel">The pixel format</typeparam>
/// <param name="color">the color</param>
/// <returns>true if the color can be considered opaque</returns>
/// <remarks>
/// Blending and composition is an expensive operation, in some cases, like
/// filling with a solid color, the blending can be avoided by a plain color replacement.
/// This method can be useful for such processors to select the fast path.
/// </remarks>
internal bool IsOpaqueColorWithoutBlending<TPixel>(TPixel color)
where TPixel : struct, IPixel<TPixel>
{
if (this.ColorBlendingMode != PixelColorBlendingMode.Normal)
{
return false;
}
if (this.AlphaCompositionMode != PixelAlphaCompositionMode.SrcOver &&
this.AlphaCompositionMode != PixelAlphaCompositionMode.Src)
{
return false;
}
if (this.BlendPercentage != 1f)
{
return false;
}
if (color.ToVector4().W != 1f)
{
return false;
}
return true;
} }
} }
} }

2
src/ImageSharp/Image.Decode.cs

@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format); IImageDecoder decoder = DiscoverDecoder(stream, config, out IImageFormat format);
if (decoder == null) if (decoder is null)
{ {
return (null, null); return (null, null);
} }

6
src/ImageSharp/ImageExtensions.cs

@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp
string ext = Path.GetExtension(filePath); string ext = Path.GetExtension(filePath);
IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext); IImageFormat format = source.GetConfiguration().ImageFormatsManager.FindFormatByFileExtension(ext);
if (format == null) if (format is null)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:"); sb.AppendLine($"Can't find a format that is associated with the file extention '{ext}'. Registered formats with there extensions include:");
@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp
IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format); IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
if (encoder == null) if (encoder is null)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:"); sb.AppendLine($"Can't find encoder for file extention '{ext}' using image format '{format.Name}'. Registered encoders include:");
@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp
Guard.NotNull(format, nameof(format)); Guard.NotNull(format, nameof(format));
IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format); IImageEncoder encoder = source.GetConfiguration().ImageFormatsManager.FindEncoder(format);
if (encoder == null) if (encoder is null)
{ {
var sb = new StringBuilder(); var sb = new StringBuilder();
sb.AppendLine("Can't find encoder for provided mime type. Available encoded:"); sb.AppendLine("Can't find encoder for provided mime type. Available encoded:");

9
src/ImageSharp/ImageFrameCollection.cs

@ -7,7 +7,6 @@ using System.Collections.Generic;
using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Memory;
namespace SixLabors.ImageSharp namespace SixLabors.ImageSharp
{ {
@ -23,9 +22,7 @@ namespace SixLabors.ImageSharp
internal ImageFrameCollection(Image<TPixel> parent, int width, int height, TPixel backgroundColor) internal ImageFrameCollection(Image<TPixel> parent, int width, int height, TPixel backgroundColor)
{ {
Guard.NotNull(parent, nameof(parent)); this.parent = parent ?? throw new ArgumentNullException(nameof(parent));
this.parent = parent;
// Frames are already cloned within the caller // Frames are already cloned within the caller
this.frames.Add(new ImageFrame<TPixel>(parent.GetConfiguration(), width, height, backgroundColor)); this.frames.Add(new ImageFrame<TPixel>(parent.GetConfiguration(), width, height, backgroundColor));
@ -33,9 +30,7 @@ namespace SixLabors.ImageSharp
internal ImageFrameCollection(Image<TPixel> parent, int width, int height, MemorySource<TPixel> memorySource) internal ImageFrameCollection(Image<TPixel> parent, int width, int height, MemorySource<TPixel> memorySource)
{ {
Guard.NotNull(parent, nameof(parent)); this.parent = parent ?? throw new ArgumentNullException(nameof(parent));
this.parent = parent;
// Frames are already cloned within the caller // Frames are already cloned within the caller
this.frames.Add(new ImageFrame<TPixel>(parent.GetConfiguration(), width, height, memorySource)); this.frames.Add(new ImageFrame<TPixel>(parent.GetConfiguration(), width, height, memorySource));

9
src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs

@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return null; return null;
} }
if (this.data == null || this.data.Length < (this.thumbnailOffset + this.thumbnailLength)) if (this.data is null || this.data.Length < (this.thumbnailOffset + this.thumbnailLength))
{ {
return null; return null;
} }
@ -235,7 +235,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
/// <returns>The <see cref="T:byte[]"/></returns> /// <returns>The <see cref="T:byte[]"/></returns>
public byte[] ToByteArray() public byte[] ToByteArray()
{ {
if (this.values == null) if (this.values is null)
{ {
return this.data; return this.data;
} }
@ -262,7 +262,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
private void SyncResolution(ExifTag tag, double resolution) private void SyncResolution(ExifTag tag, double resolution)
{ {
ExifValue value = this.GetValue(tag); ExifValue value = this.GetValue(tag);
if (value == null)
if (value is null)
{ {
return; return;
} }
@ -283,7 +284,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
return; return;
} }
if (this.data == null) if (this.data is null)
{ {
this.values = new List<ExifValue>(); this.values = new List<ExifValue>();
return; return;

5
src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs

@ -76,7 +76,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{ {
var values = new List<ExifValue>(); var values = new List<ExifValue>();
if (this.ReadString(2) == "II") // II == 0x4949
if (this.ReadUInt16() == 0x4949)
{ {
this.endianness = Endianness.LittleEndian; this.endianness = Endianness.LittleEndian;
} }
@ -202,7 +203,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
private object ConvertValue(ExifDataType dataType, ReadOnlySpan<byte> buffer, uint numberOfComponents) private object ConvertValue(ExifDataType dataType, ReadOnlySpan<byte> buffer, uint numberOfComponents)
{ {
if (buffer == null || buffer.Length == 0) if (buffer.Length == 0)
{ {
return null; return null;
} }

7
src/ImageSharp/MetaData/Profiles/Exif/ExifTagDescriptionAttribute.cs

@ -12,8 +12,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
[AttributeUsage(AttributeTargets.Field, AllowMultiple = true)] [AttributeUsage(AttributeTargets.Field, AllowMultiple = true)]
internal sealed class ExifTagDescriptionAttribute : Attribute internal sealed class ExifTagDescriptionAttribute : Attribute
{ {
private object value; private readonly object value;
private string description; private readonly string description;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ExifTagDescriptionAttribute"/> class. /// Initializes a new instance of the <see cref="ExifTagDescriptionAttribute"/> class.
@ -37,7 +37,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
public static string GetDescription(ExifTag tag, object value) public static string GetDescription(ExifTag tag, object value)
{ {
FieldInfo field = tag.GetType().GetTypeInfo().GetDeclaredField(tag.ToString()); FieldInfo field = tag.GetType().GetTypeInfo().GetDeclaredField(tag.ToString());
if (field == null)
if (field is null)
{ {
return null; return null;
} }

10
src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs

@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{ {
get get
{ {
if (this.Value == null) if (this.Value is null)
{ {
return false; return false;
} }
@ -101,7 +101,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
{ {
get get
{ {
if (this.Value == null) if (this.Value is null)
{ {
return 4; return 4;
} }
@ -213,7 +213,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
/// <inheritdoc/> /// <inheritdoc/>
public override string ToString() public override string ToString()
{ {
if (this.Value == null) if (this.Value is null)
{ {
return null; return null;
} }
@ -589,7 +589,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
type = type.GetElementType(); type = type.GetElementType();
} }
if (type == null || type == typeof(ushort)) if (type is null || type == typeof(ushort))
{ {
return new ExifValue(tag, ExifDataType.Short, value, isArray); return new ExifValue(tag, ExifDataType.Short, value, isArray);
} }
@ -616,7 +616,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
/// </exception> /// </exception>
private void CheckValue(object value) private void CheckValue(object value)
{ {
if (value == null) if (value is null)
{ {
return; return;
} }

6
src/ImageSharp/MetaData/Profiles/Exif/ExifWriter.cs

@ -20,9 +20,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif
private ExifParts allowedParts; private ExifParts allowedParts;
private IList<ExifValue> values; private IList<ExifValue> values;
private List<int> dataOffsets; private List<int> dataOffsets;
private List<int> ifdIndexes; private readonly List<int> ifdIndexes;
private List<int> exifIndexes; private readonly List<int> exifIndexes;
private List<int> gpsIndexes; private readonly List<int> gpsIndexes;
/// <summary> /// <summary>
/// Initializes a new instance of the <see cref="ExifWriter"/> class. /// Initializes a new instance of the <see cref="ExifWriter"/> class.

4
src/ImageSharp/MetaData/Profiles/ICC/Curves/IccCurveSegment.cs

@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public virtual bool Equals(IccCurveSegment other) public virtual bool Equals(IccCurveSegment other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }
@ -40,4 +40,4 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
return this.Signature == other.Signature; return this.Signature == other.Signature;
} }
} }
} }

2
src/ImageSharp/MetaData/Profiles/ICC/Curves/IccOneDimensionalCurve.cs

@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc /> /// <inheritdoc />
public bool Equals(IccOneDimensionalCurve other) public bool Equals(IccOneDimensionalCurve other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/Curves/IccResponseCurve.cs

@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccResponseCurve other) public bool Equals(IccResponseCurve other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

4
src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.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.Text; using System.Text;
namespace SixLabors.ImageSharp.MetaData.Profiles.Icc namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
@ -28,8 +29,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <param name="data">The data to read</param> /// <param name="data">The data to read</param>
public IccDataReader(byte[] data) public IccDataReader(byte[] data)
{ {
Guard.NotNull(data, nameof(data)); this.data = data ?? throw new ArgumentNullException(nameof(data));
this.data = data;
} }
/// <summary> /// <summary>

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

@ -199,7 +199,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
Guard.MustBeGreaterThan(length, 0, nameof(length)); Guard.MustBeGreaterThan(length, 0, nameof(length));
if (value == null) if (value is null)
{ {
value = string.Empty; value = string.Empty;
} }

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

@ -901,7 +901,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
{ {
int size, count = 0; int size, count = 0;
if (value.Ascii == null) if (value.Ascii is null)
{ {
count += this.WriteUInt32(0); count += this.WriteUInt32(0);
} }
@ -914,7 +914,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
this.dataStream.Position += size; this.dataStream.Position += size;
} }
if (value.Unicode == null) if (value.Unicode is null)
{ {
count += this.WriteUInt32(0); count += this.WriteUInt32(0);
count += this.WriteUInt32(0); count += this.WriteUInt32(0);
@ -929,7 +929,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
this.dataStream.Position += size; this.dataStream.Position += size;
} }
if (value.ScriptCode == null) if (value.ScriptCode is null)
{ {
count += this.WriteUInt16(0); count += this.WriteUInt16(0);
count += this.WriteByte(0); count += this.WriteByte(0);

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

@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <summary> /// <summary>
/// The byte array to read the ICC profile from /// The byte array to read the ICC profile from
/// </summary> /// </summary>
private byte[] data; private readonly byte[] data;
/// <summary> /// <summary>
/// The backing file for the <see cref="Entries"/> property /// The backing file for the <see cref="Entries"/> property
@ -200,7 +200,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
return; return;
} }
if (this.data == null) if (this.data is null)
{ {
this.header = new IccProfileHeader(); this.header = new IccProfileHeader();
return; return;
@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
return; return;
} }
if (this.data == null) if (this.data is null)
{ {
this.entries = new List<IccTagDataEntry>(); this.entries = new List<IccTagDataEntry>();
return; return;

2
src/ImageSharp/MetaData/Profiles/ICC/IccTagDataEntry.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public virtual bool Equals(IccTagDataEntry other) public virtual bool Equals(IccTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

3
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccClutProcessElement.cs

@ -17,8 +17,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccClutProcessElement(IccClut clutValue) public IccClutProcessElement(IccClut clutValue)
: base(IccMultiProcessElementSignature.Clut, clutValue?.InputChannelCount ?? 1, clutValue?.OutputChannelCount ?? 1) : base(IccMultiProcessElementSignature.Clut, clutValue?.InputChannelCount ?? 1, clutValue?.OutputChannelCount ?? 1)
{ {
Guard.NotNull(clutValue, nameof(clutValue)); this.ClutValue = clutValue ?? throw new ArgumentNullException(nameof(clutValue));
this.ClutValue = clutValue;
} }
/// <summary> /// <summary>

3
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccCurveSetProcessElement.cs

@ -18,8 +18,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccCurveSetProcessElement(IccOneDimensionalCurve[] curves) public IccCurveSetProcessElement(IccOneDimensionalCurve[] curves)
: base(IccMultiProcessElementSignature.CurveSet, curves?.Length ?? 1, curves?.Length ?? 1) : base(IccMultiProcessElementSignature.CurveSet, curves?.Length ?? 1, curves?.Length ?? 1)
{ {
Guard.NotNull(curves, nameof(curves)); this.Curves = curves ?? throw new ArgumentNullException(nameof(curves));
this.Curves = curves;
} }
/// <summary> /// <summary>

2
src/ImageSharp/MetaData/Profiles/ICC/MultiProcessElements/IccMultiProcessElement.cs

@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public virtual bool Equals(IccMultiProcessElement other) public virtual bool Equals(IccMultiProcessElement other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccChromaticityTagDataEntry.cs

@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
this.ChannelValues = channelValues; this.ChannelValues = channelValues;
int channelLength = channelValues[0].Length; int channelLength = channelValues[0].Length;
bool channelsNotSame = channelValues.Any(t => t == null || t.Length != channelLength); bool channelsNotSame = channelValues.Any(t => t is null || t.Length != channelLength);
Guard.IsFalse(channelsNotSame, nameof(channelValues), "The number of values per channel is not the same for all channels"); Guard.IsFalse(channelsNotSame, nameof(channelValues), "The number of values per channel is not the same for all channels");
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccColorantOrderTagDataEntry.cs

@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccColorantOrderTagDataEntry other) public bool Equals(IccColorantOrderTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccColorantTableTagDataEntry.cs

@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccColorantTableTagDataEntry other) public bool Equals(IccColorantTableTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCrdInfoTagDataEntry.cs

@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccCrdInfoTagDataEntry other) public bool Equals(IccCrdInfoTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccCurveTagDataEntry.cs

@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccCurveTagDataEntry other) public bool Equals(IccCurveTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

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

@ -42,8 +42,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccDataTagDataEntry(byte[] data, bool isAscii, IccProfileTag tagSignature) public IccDataTagDataEntry(byte[] data, bool isAscii, IccProfileTag tagSignature)
: base(IccTypeSignature.Data, tagSignature) : base(IccTypeSignature.Data, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentException(nameof(data));
this.Data = data;
this.IsAscii = isAscii; this.IsAscii = isAscii;
} }
@ -72,7 +71,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccDataTagDataEntry other) public bool Equals(IccDataTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDateTimeTagDataEntry.cs

@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccDateTimeTagDataEntry other) public bool Equals(IccDateTimeTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

5
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccFix16ArrayTagDataEntry.cs

@ -27,8 +27,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccFix16ArrayTagDataEntry(float[] data, IccProfileTag tagSignature) public IccFix16ArrayTagDataEntry(float[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.S15Fixed16Array, tagSignature) : base(IccTypeSignature.S15Fixed16Array, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentNullException(nameof(data));
this.Data = data;
} }
/// <summary> /// <summary>
@ -45,7 +44,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccFix16ArrayTagDataEntry other) public bool Equals(IccFix16ArrayTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLut16TagDataEntry.cs

@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccLut16TagDataEntry other) public bool Equals(IccLut16TagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLut8TagDataEntry.cs

@ -120,7 +120,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccLut8TagDataEntry other) public bool Equals(IccLut8TagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

10
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLutAToBTagDataEntry.cs

@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccLutAToBTagDataEntry other) public bool Equals(IccLutAToBTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }
@ -200,8 +200,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
private bool EqualsCurve(IccTagDataEntry[] thisCurves, IccTagDataEntry[] entryCurves) private bool EqualsCurve(IccTagDataEntry[] thisCurves, IccTagDataEntry[] entryCurves)
{ {
bool thisNull = thisCurves == null; bool thisNull = thisCurves is null;
bool entryNull = entryCurves == null; bool entryNull = entryCurves is null;
if (thisNull && entryNull) if (thisNull && entryNull)
{ {
@ -271,7 +271,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
private Vector3? CreateMatrix3x1(float[] matrix) private Vector3? CreateMatrix3x1(float[] matrix)
{ {
if (matrix == null) if (matrix is null)
{ {
return null; return null;
} }
@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
private Matrix4x4? CreateMatrix3x3(float[,] matrix) private Matrix4x4? CreateMatrix3x3(float[,] matrix)
{ {
if (matrix == null) if (matrix is null)
{ {
return null; return null;
} }

10
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccLutBToATagDataEntry.cs

@ -153,7 +153,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccLutBToATagDataEntry other) public bool Equals(IccLutBToATagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }
@ -200,8 +200,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
private bool EqualsCurve(IccTagDataEntry[] thisCurves, IccTagDataEntry[] entryCurves) private bool EqualsCurve(IccTagDataEntry[] thisCurves, IccTagDataEntry[] entryCurves)
{ {
bool thisNull = thisCurves == null; bool thisNull = thisCurves is null;
bool entryNull = entryCurves == null; bool entryNull = entryCurves is null;
if (thisNull && entryNull) if (thisNull && entryNull)
{ {
@ -271,7 +271,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
private Vector3? CreateMatrix3x1(float[] matrix) private Vector3? CreateMatrix3x1(float[] matrix)
{ {
if (matrix == null) if (matrix is null)
{ {
return null; return null;
} }
@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
private Matrix4x4? CreateMatrix3x3(float[,] matrix) private Matrix4x4? CreateMatrix3x3(float[,] matrix)
{ {
if (matrix == null) if (matrix is null)
{ {
return null; return null;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMeasurementTagDataEntry.cs

@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccMeasurementTagDataEntry other) public bool Equals(IccMeasurementTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

5
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMultiLocalizedUnicodeTagDataEntry.cs

@ -29,8 +29,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccMultiLocalizedUnicodeTagDataEntry(IccLocalizedString[] texts, IccProfileTag tagSignature) public IccMultiLocalizedUnicodeTagDataEntry(IccLocalizedString[] texts, IccProfileTag tagSignature)
: base(IccTypeSignature.MultiLocalizedUnicode, tagSignature) : base(IccTypeSignature.MultiLocalizedUnicode, tagSignature)
{ {
Guard.NotNull(texts, nameof(texts)); this.Texts = texts ?? throw new ArgumentNullException(nameof(texts));
this.Texts = texts;
} }
/// <summary> /// <summary>
@ -47,7 +46,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccMultiLocalizedUnicodeTagDataEntry other) public bool Equals(IccMultiLocalizedUnicodeTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccMultiProcessElementsTagDataEntry.cs

@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccMultiProcessElementsTagDataEntry other) public bool Equals(IccMultiProcessElementsTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

3
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccProfileSequenceDescTagDataEntry.cs

@ -30,8 +30,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccProfileSequenceDescTagDataEntry(IccProfileDescription[] descriptions, IccProfileTag tagSignature) public IccProfileSequenceDescTagDataEntry(IccProfileDescription[] descriptions, IccProfileTag tagSignature)
: base(IccTypeSignature.ProfileSequenceDesc, tagSignature) : base(IccTypeSignature.ProfileSequenceDesc, tagSignature)
{ {
Guard.NotNull(descriptions, nameof(descriptions)); this.Descriptions = descriptions ?? throw new ArgumentNullException(nameof(descriptions));
this.Descriptions = descriptions;
} }
/// <summary> /// <summary>

3
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccProfileSequenceIdentifierTagDataEntry.cs

@ -28,8 +28,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccProfileSequenceIdentifierTagDataEntry(IccProfileSequenceIdentifier[] data, IccProfileTag tagSignature) public IccProfileSequenceIdentifierTagDataEntry(IccProfileSequenceIdentifier[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.ProfileSequenceIdentifier, tagSignature) : base(IccTypeSignature.ProfileSequenceIdentifier, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentNullException(nameof(data));
this.Data = data;
} }
/// <summary> /// <summary>

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

@ -30,10 +30,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccScreeningTagDataEntry(IccScreeningFlag flags, IccScreeningChannel[] channels, IccProfileTag tagSignature) public IccScreeningTagDataEntry(IccScreeningFlag flags, IccScreeningChannel[] channels, IccProfileTag tagSignature)
: base(IccTypeSignature.Screening, tagSignature) : base(IccTypeSignature.Screening, tagSignature)
{ {
Guard.NotNull(channels, nameof(channels));
this.Flags = flags; this.Flags = flags;
this.Channels = channels; this.Channels = channels ?? throw new ArgumentNullException(nameof(channels));
} }
/// <summary> /// <summary>

5
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccSignatureTagDataEntry.cs

@ -28,12 +28,11 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccSignatureTagDataEntry(string signatureData, IccProfileTag tagSignature) public IccSignatureTagDataEntry(string signatureData, IccProfileTag tagSignature)
: base(IccTypeSignature.Signature, tagSignature) : base(IccTypeSignature.Signature, tagSignature)
{ {
Guard.NotNull(signatureData, nameof(signatureData)); this.SignatureData = signatureData ?? throw new ArgumentNullException(nameof(signatureData));
this.SignatureData = signatureData;
} }
/// <summary> /// <summary>
/// Gets the Signature /// Gets the signature data
/// </summary> /// </summary>
public string SignatureData { get; } public string SignatureData { get; }

2
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccTextDescriptionTagDataEntry.cs

@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <returns>The converted entry</returns> /// <returns>The converted entry</returns>
public static explicit operator IccMultiLocalizedUnicodeTagDataEntry(IccTextDescriptionTagDataEntry textEntry) public static explicit operator IccMultiLocalizedUnicodeTagDataEntry(IccTextDescriptionTagDataEntry textEntry)
{ {
if (textEntry == null) if (textEntry is null)
{ {
return null; return null;
} }

3
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccTextTagDataEntry.cs

@ -27,8 +27,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccTextTagDataEntry(string text, IccProfileTag tagSignature) public IccTextTagDataEntry(string text, IccProfileTag tagSignature)
: base(IccTypeSignature.Text, tagSignature) : base(IccTypeSignature.Text, tagSignature)
{ {
Guard.NotNull(text, nameof(text)); this.Text = text ?? throw new ArgumentNullException(nameof(text));
this.Text = text;
} }
/// <summary> /// <summary>

3
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUFix16ArrayTagDataEntry.cs

@ -27,8 +27,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccUFix16ArrayTagDataEntry(float[] data, IccProfileTag tagSignature) public IccUFix16ArrayTagDataEntry(float[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.U16Fixed16Array, tagSignature) : base(IccTypeSignature.U16Fixed16Array, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentNullException(nameof(data));
this.Data = data;
} }
/// <summary> /// <summary>

3
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt16ArrayTagDataEntry.cs

@ -27,8 +27,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccUInt16ArrayTagDataEntry(ushort[] data, IccProfileTag tagSignature) public IccUInt16ArrayTagDataEntry(ushort[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.UInt16Array, tagSignature) : base(IccTypeSignature.UInt16Array, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentNullException(nameof(data));
this.Data = data;
} }
/// <summary> /// <summary>

5
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt32ArrayTagDataEntry.cs

@ -27,8 +27,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccUInt32ArrayTagDataEntry(uint[] data, IccProfileTag tagSignature) public IccUInt32ArrayTagDataEntry(uint[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.UInt32Array, tagSignature) : base(IccTypeSignature.UInt32Array, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentNullException(nameof(data));
this.Data = data;
} }
/// <summary> /// <summary>
@ -45,7 +44,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccUInt32ArrayTagDataEntry other) public bool Equals(IccUInt32ArrayTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

5
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt64ArrayTagDataEntry.cs

@ -28,8 +28,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccUInt64ArrayTagDataEntry(ulong[] data, IccProfileTag tagSignature) public IccUInt64ArrayTagDataEntry(ulong[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.UInt64Array, tagSignature) : base(IccTypeSignature.UInt64Array, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentNullException(nameof(data));
this.Data = data;
} }
/// <summary> /// <summary>
@ -46,7 +45,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccUInt64ArrayTagDataEntry other) public bool Equals(IccUInt64ArrayTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

5
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUInt8ArrayTagDataEntry.cs

@ -27,8 +27,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccUInt8ArrayTagDataEntry(byte[] data, IccProfileTag tagSignature) public IccUInt8ArrayTagDataEntry(byte[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.UInt8Array, tagSignature) : base(IccTypeSignature.UInt8Array, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentNullException(nameof(data));
this.Data = data;
} }
/// <summary> /// <summary>
@ -45,7 +44,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccUInt8ArrayTagDataEntry other) public bool Equals(IccUInt8ArrayTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

12
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUcrBgTagDataEntry.cs

@ -32,13 +32,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccUcrBgTagDataEntry(ushort[] ucrCurve, ushort[] bgCurve, string description, IccProfileTag tagSignature) public IccUcrBgTagDataEntry(ushort[] ucrCurve, ushort[] bgCurve, string description, IccProfileTag tagSignature)
: base(IccTypeSignature.UcrBg, tagSignature) : base(IccTypeSignature.UcrBg, tagSignature)
{ {
Guard.NotNull(ucrCurve, nameof(ucrCurve)); this.UcrCurve = ucrCurve ?? throw new ArgumentNullException(nameof(ucrCurve));
Guard.NotNull(bgCurve, nameof(bgCurve)); this.BgCurve = bgCurve ?? throw new ArgumentNullException(nameof(bgCurve));
Guard.NotNull(description, nameof(description)); this.Description = description ?? throw new ArgumentNullException(nameof(description));
this.UcrCurve = ucrCurve;
this.BgCurve = bgCurve;
this.Description = description;
} }
/// <summary> /// <summary>
@ -65,7 +61,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccUcrBgTagDataEntry other) public bool Equals(IccUcrBgTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

5
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccUnknownTagDataEntry.cs

@ -27,8 +27,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccUnknownTagDataEntry(byte[] data, IccProfileTag tagSignature) public IccUnknownTagDataEntry(byte[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.Unknown, tagSignature) : base(IccTypeSignature.Unknown, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentNullException(nameof(data));
this.Data = data;
} }
/// <summary> /// <summary>
@ -45,7 +44,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccUnknownTagDataEntry other) public bool Equals(IccUnknownTagDataEntry other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

3
src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccXyzTagDataEntry.cs

@ -28,8 +28,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
public IccXyzTagDataEntry(Vector3[] data, IccProfileTag tagSignature) public IccXyzTagDataEntry(Vector3[] data, IccProfileTag tagSignature)
: base(IccTypeSignature.Xyz, tagSignature) : base(IccTypeSignature.Xyz, tagSignature)
{ {
Guard.NotNull(data, nameof(data)); this.Data = data ?? throw new ArgumentNullException(nameof(data));
this.Data = data;
} }
/// <summary> /// <summary>

2
src/ImageSharp/MetaData/Profiles/ICC/Various/IccClut.cs

@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(IccClut other) public bool Equals(IccClut other)
{ {
if (other == null) if (other is null)
{ {
return false; return false;
} }

4
src/ImageSharp/MetaData/Profiles/ICC/Various/IccColorantTableEntry.cs

@ -28,9 +28,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <param name="pcs3">Third PCS value</param> /// <param name="pcs3">Third PCS value</param>
public IccColorantTableEntry(string name, ushort pcs1, ushort pcs2, ushort pcs3) public IccColorantTableEntry(string name, ushort pcs1, ushort pcs2, ushort pcs3)
{ {
Guard.NotNull(name, nameof(name)); this.Name = name ?? throw new ArgumentNullException(nameof(name));
this.Name = name;
this.Pcs1 = pcs1; this.Pcs1 = pcs1;
this.Pcs2 = pcs2; this.Pcs2 = pcs2;
this.Pcs3 = pcs3; this.Pcs3 = pcs3;

7
src/ImageSharp/MetaData/Profiles/ICC/Various/IccLocalizedString.cs

@ -29,11 +29,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <param name="text">The text value of this string</param> /// <param name="text">The text value of this string</param>
public IccLocalizedString(CultureInfo culture, string text) public IccLocalizedString(CultureInfo culture, string text)
{ {
Guard.NotNull(culture, nameof(culture)); this.Culture = culture ?? throw new ArgumentNullException(nameof(culture));
Guard.NotNull(text, nameof(text)); this.Text = text ?? throw new ArgumentNullException(nameof(text));
this.Culture = culture;
this.Text = text;
} }
/// <summary> /// <summary>

3
src/ImageSharp/MetaData/Profiles/ICC/Various/IccLut.cs

@ -16,8 +16,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc
/// <param name="values">The LUT values</param> /// <param name="values">The LUT values</param>
public IccLut(float[] values) public IccLut(float[] values)
{ {
Guard.NotNull(values, nameof(values)); this.Values = values ?? throw new ArgumentNullException(nameof(values));
this.Values = values;
} }
/// <summary> /// <summary>

5
src/ImageSharp/PixelFormats/Alpha8.cs

@ -208,10 +208,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <summary> /// <summary>
/// Packs a <see cref="float"/> into a byte. /// Packs a <see cref="float"/> into a byte.

7
src/ImageSharp/PixelFormats/Argb32.cs

@ -362,12 +362,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc/> /// <inheritdoc/>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode() => this.Argb.GetHashCode();
{
int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
hash = HashHelpers.Combine(hash, this.B.GetHashCode());
return HashHelpers.Combine(hash, this.A.GetHashCode());
}
/// <summary> /// <summary>
/// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1] /// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1]

5
src/ImageSharp/PixelFormats/Bgr565.cs

@ -224,10 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <summary> /// <summary>
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>. /// Packs the <see cref="float"/> components into a <see cref="ushort"/>.

10
src/ImageSharp/PixelFormats/Bgra32.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;
@ -105,19 +104,14 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc/> /// <inheritdoc/>
public bool Equals(Bgra32 other) public bool Equals(Bgra32 other)
{ {
return this.R == other.R && this.G == other.G && this.B == other.B && this.A == other.A; return this.Bgra == other.Bgra;
} }
/// <inheritdoc/> /// <inheritdoc/>
public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other); public override bool Equals(object obj) => obj is Bgra32 other && this.Equals(other);
/// <inheritdoc/> /// <inheritdoc/>
public override int GetHashCode() public override int GetHashCode() => this.Bgra.GetHashCode();
{
int hash = HashHelpers.Combine(this.R.GetHashCode(), this.G.GetHashCode());
hash = HashHelpers.Combine(hash, this.B.GetHashCode());
return HashHelpers.Combine(hash, this.A.GetHashCode());
}
/// <summary> /// <summary>
/// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1] /// Gets the <see cref="Vector4"/> representation without normalizing to [0, 1]

5
src/ImageSharp/PixelFormats/Bgra4444.cs

@ -215,10 +215,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <summary> /// <summary>
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>. /// Packs the <see cref="float"/> components into a <see cref="ushort"/>.

5
src/ImageSharp/PixelFormats/Bgra5551.cs

@ -221,10 +221,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// </summary> /// </summary>
/// <returns>The hash code for the packed vector.</returns> /// <returns>The hash code for the packed vector.</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <summary> /// <summary>
/// Packs the <see cref="float"/> components into a <see cref="ushort"/>. /// Packs the <see cref="float"/> components into a <see cref="ushort"/>.

5
src/ImageSharp/PixelFormats/Byte4.cs

@ -210,10 +210,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <summary> /// <summary>
/// Returns a string representation of the current instance. /// Returns a string representation of the current instance.

2
src/ImageSharp/PixelFormats/ColorBuilder{TPixel}.cs

@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.PixelFormats
hex = ToRgbaHex(hex); hex = ToRgbaHex(hex);
if (hex == null || !uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint packedValue)) if (hex is null || !uint.TryParse(hex, NumberStyles.HexNumber, CultureInfo.InvariantCulture, out uint packedValue))
{ {
throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex)); throw new ArgumentException("Hexadecimal string is not in the correct format.", nameof(hex));
} }

5
src/ImageSharp/PixelFormats/HalfSingle.cs

@ -229,10 +229,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
private Vector4 ToByteScaledVector4() private Vector4 ToByteScaledVector4()

5
src/ImageSharp/PixelFormats/HalfVector2.cs

@ -231,10 +231,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj)

5
src/ImageSharp/PixelFormats/HalfVector4.cs

@ -224,10 +224,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() public override int GetHashCode() => this.PackedValue.GetHashCode();
{
return this.PackedValue.GetHashCode();
}
/// <inheritdoc /> /// <inheritdoc />
public override bool Equals(object obj) public override bool Equals(object obj)

5
src/ImageSharp/PixelFormats/NormalizedByte2.cs

@ -257,10 +257,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
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()

5
src/ImageSharp/PixelFormats/NormalizedByte4.cs

@ -250,10 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <inheritdoc /> /// <inheritdoc />
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
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()

63
src/ImageSharp/PixelFormats/PixelBlenderMode.cs → src/ImageSharp/PixelFormats/PixelAlphaCompositionMode.cs

@ -4,55 +4,15 @@
namespace SixLabors.ImageSharp.PixelFormats namespace SixLabors.ImageSharp.PixelFormats
{ {
/// <summary> /// <summary>
/// Enumerates the various blending modes. /// Enumerates the various alpha composition modes.
/// </summary> /// </summary>
public enum PixelBlenderMode public enum PixelAlphaCompositionMode
{ {
/// <summary> /// <summary>
/// Default blending mode, also known as "Normal" or "Alpha Blending" /// returns the destination over the source.
/// </summary>
Normal = 0,
/// <summary>
/// Blends the 2 values by multiplication.
/// </summary>
Multiply,
/// <summary>
/// Blends the 2 values by addition.
/// </summary>
Add,
/// <summary>
/// Blends the 2 values by subtraction.
/// </summary>
Subtract,
/// <summary>
/// Multiplies the complements of the backdrop and source values, then complements the result.
/// </summary>
Screen,
/// <summary>
/// Selects the minimum of the backdrop and source values.
/// </summary>
Darken,
/// <summary>
/// Selects the max of the backdrop and source values.
/// </summary>
Lighten,
/// <summary>
/// Multiplies or screens the values, depending on the backdrop vector values.
/// </summary>
Overlay,
/// <summary>
/// Multiplies or screens the colors, depending on the source value.
/// </summary> /// </summary>
HardLight, SrcOver = 0,
/// <summary> /// <summary>
/// returns the source colors. /// returns the source colors.
/// </summary> /// </summary>
@ -61,22 +21,17 @@ namespace SixLabors.ImageSharp.PixelFormats
/// <summary> /// <summary>
/// returns the source over the destination. /// returns the source over the destination.
/// </summary> /// </summary>
Atop, SrcAtop,
/// <summary>
/// returns the destination over the source.
/// </summary>
Over,
/// <summary> /// <summary>
/// The source where the destination and source overlap. /// The source where the destination and source overlap.
/// </summary> /// </summary>
In, SrcIn,
/// <summary> /// <summary>
/// The destination where the destination and source overlap. /// The destination where the destination and source overlap.
/// </summary> /// </summary>
Out, SrcOut,
/// <summary> /// <summary>
/// The destination where the source does not overlap it. /// The destination where the source does not overlap it.

3561
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs

File diff suppressed because it is too large

48
src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt

@ -35,10 +35,22 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
{ {
<# <#
string[] composers = new []{
"Src",
"SrcAtop",
"SrcOver",
"SrcIn",
"SrcOut",
"Dest",
"DestAtop",
"DestOver",
"DestIn",
"DestOut",
"Clear",
"Xor",
};
string[] blenders = new []{ string[] blenders = new []{
"Normal", "Normal",
"Multiply", "Multiply",
"Add", "Add",
@ -47,36 +59,26 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
"Darken", "Darken",
"Lighten", "Lighten",
"Overlay", "Overlay",
"HardLight", "HardLight"
"Src" ,
"Atop" ,
"Over" ,
"In" ,
"Out" ,
"Dest" ,
"DestAtop" ,
"DestOver" ,
"DestIn" ,
"DestOut" ,
"Clear" ,
"Xor" ,
}; };
foreach(var composer in composers) {
foreach(var blender in blenders) { foreach(var blender in blenders) {
string blender_composer= $"{blender}{composer}";
#> #>
internal class <#=blender#> : PixelBlender<TPixel> internal class <#= blender_composer#> : PixelBlender<TPixel>
{ {
/// <summary> /// <summary>
/// Gets the static instance of this blender. /// Gets the static instance of this blender.
/// </summary> /// </summary>
public static <#=blender#> Instance { get; } = new <#=blender#>(); public static <#=blender_composer#> Instance { get; } = new <#=blender_composer#>();
/// <inheritdoc /> /// <inheritdoc />
public override TPixel Blend(TPixel background, TPixel source, float amount) public override TPixel Blend(TPixel background, TPixel source, float amount)
{ {
return PorterDuffFunctions.<#=blender#>(background, source, amount); return PorterDuffFunctions.<#=blender_composer#>(background, source, amount);
} }
/// <inheritdoc /> /// <inheritdoc />
@ -97,7 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
for (int i = 0; i < destination.Length; i++) for (int i = 0; i < destination.Length; i++)
{ {
destinationSpan[i] = PorterDuffFunctions.<#=blender#>(backgroundSpan[i], sourceSpan[i], amount[i]); destinationSpan[i] = PorterDuffFunctions.<#=blender_composer#>(backgroundSpan[i], sourceSpan[i], amount[i]);
} }
PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length); PixelOperations<TPixel>.Instance.PackFromVector4(destinationSpan, destination, destination.Length);
@ -106,7 +108,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
} }
<# <#
}
} }
#> #>

2600
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs

File diff suppressed because it is too large

298
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt

@ -1,112 +1,188 @@
<# <#
// 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.
#> #>
<#@ template debug="false" hostspecific="false" language="C#" #> <#@ template debug="false" hostspecific="false" language="C#" #>
<#@ assembly name="System.Core" #> <#@ assembly name="System.Core" #>
<#@ import namespace="System.Linq" #> <#@ import namespace="System.Linq" #>
<#@ import namespace="System.Text" #> <#@ import namespace="System.Text" #>
<#@ import namespace="System.Collections.Generic" #> <#@ import namespace="System.Collections.Generic" #>
<#@ output extension=".cs" #> <#@ output extension=".cs" #>
// 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.
// <auto-generated /> // <auto-generated />
using System; using System;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
{ {
internal static partial class PorterDuffFunctions internal static partial class PorterDuffFunctions
{ {
<#
<# void GeneratePixelBlenders(string blender) { #>
void GeneratePixelBlender (string blender)
{ [MethodImpl(MethodImplOptions.AggressiveInlining)]
#> public static Vector4 <#=blender#>Src(Vector4 backdrop, Vector4 source, float opacity)
[MethodImpl(MethodImplOptions.AggressiveInlining)] {
public static TPixel <#=blender#><TPixel>(TPixel backdrop, TPixel source, float amount) opacity = opacity.Clamp(0, 1);
where TPixel : struct, IPixel<TPixel> source.W *= opacity;
{
TPixel dest = default; return source;
dest.PackFromVector4(<#=blender#>(backdrop.ToVector4(), source.ToVector4(), amount)); }
return dest;
} [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 <#=blender#>SrcAtop(Vector4 backdrop, Vector4 source, float opacity)
<# {
} opacity = opacity.Clamp(0, 1);
source.W *= opacity;
void GenerateVectorCompositor(string name, string sourceVar, string destVar, string blendVar)
{ return Atop(backdrop, source, <#=blender#>(backdrop, source));
int a_s = sourceVar == "Vector4.Zero" ? 0 : 1; }
int a_b = destVar == "Vector4.Zero" ? 0 : 1;
int a_x = blendVar == "Vector4.Zero" ? 0 : 1; [MethodImpl(MethodImplOptions.AggressiveInlining)]
#> public static Vector4 <#=blender#>SrcOver(Vector4 backdrop, Vector4 source, float opacity)
[MethodImpl(MethodImplOptions.AggressiveInlining)] {
public static Vector4 <#=name#>(Vector4 backdrop, Vector4 source, float opacity) opacity = opacity.Clamp(0, 1);
{ source.W *= opacity;
opacity = opacity.Clamp(0, 1);
<# if(sourceVar != "Vector4.Zero" ) { #> return Over(backdrop, source, <#=blender#>(backdrop, source));
source.W *= opacity; }
<# } #>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
// calculate weights public static Vector4 <#=blender#>SrcIn(Vector4 backdrop, Vector4 source, float opacity)
float xw = backdrop.W * source.W; {
float bw = backdrop.W - xw; opacity = opacity.Clamp(0, 1);
float sw = source.W - xw; source.W *= opacity;
// calculate final alpha return In(backdrop, source, <#=blender#>(backdrop, source));
float fw = (sw * <#=a_s#>) + (bw * <#=a_b#>) + (xw * <#=a_x#>); }
// calculate final value [MethodImpl(MethodImplOptions.AggressiveInlining)]
Vector4 xform = ((<#=blendVar#> * xw) + (<#=destVar#> * bw) + (<#=sourceVar#> * sw)) / MathF.Max(fw, Constants.Epsilon); public static Vector4 <#=blender#>SrcOut(Vector4 backdrop, Vector4 source, float opacity)
xform.W = fw; {
opacity = opacity.Clamp(0, 1);
return Vector4.Lerp(backdrop, xform, opacity); source.W *= opacity;
}
return Out(backdrop, source);
<# }
}
GenerateVectorCompositor("Src", "source", "Vector4.Zero", "source"); [MethodImpl(MethodImplOptions.AggressiveInlining)]
GenerateVectorCompositor("Atop", "Vector4.Zero", "backdrop", "source"); public static Vector4 <#=blender#>Dest(Vector4 backdrop, Vector4 source, float opacity)
GenerateVectorCompositor("Over", "source", "backdrop", "source"); {
GenerateVectorCompositor("In", "Vector4.Zero", "Vector4.Zero", "source"); return backdrop;
GenerateVectorCompositor("Out", "source", "Vector4.Zero", "Vector4.Zero"); }
GenerateVectorCompositor("Dest", "Vector4.Zero", "backdrop", "backdrop");
GenerateVectorCompositor("DestAtop", "source", "Vector4.Zero", "backdrop"); [MethodImpl(MethodImplOptions.AggressiveInlining)]
GenerateVectorCompositor("DestOver", "source", "backdrop", "backdrop"); public static Vector4 <#=blender#>DestAtop(Vector4 backdrop, Vector4 source, float opacity)
GenerateVectorCompositor("DestIn", "Vector4.Zero", "Vector4.Zero", "backdrop"); {
GenerateVectorCompositor("DestOut", "Vector4.Zero", "backdrop", "Vector4.Zero"); opacity = opacity.Clamp(0, 1);
GenerateVectorCompositor("Clear", "Vector4.Zero", "Vector4.Zero", "Vector4.Zero"); source.W *= opacity;
GenerateVectorCompositor("Xor", "source", "backdrop", "Vector4.Zero");
return Atop(source, backdrop, <#=blender#>(source, backdrop));
}
GeneratePixelBlender("Normal");
GeneratePixelBlender("Multiply"); [MethodImpl(MethodImplOptions.AggressiveInlining)]
GeneratePixelBlender("Add"); public static Vector4 <#=blender#>DestOver(Vector4 backdrop, Vector4 source, float opacity)
GeneratePixelBlender("Subtract"); {
GeneratePixelBlender("Screen"); opacity = opacity.Clamp(0, 1);
GeneratePixelBlender("Darken"); source.W *= opacity;
GeneratePixelBlender("Lighten");
GeneratePixelBlender("Overlay"); return Over(source, backdrop, <#=blender#>(source, backdrop));
GeneratePixelBlender("HardLight"); }
GeneratePixelBlender("Src"); [MethodImpl(MethodImplOptions.AggressiveInlining)]
GeneratePixelBlender("Atop"); public static Vector4 <#=blender#>DestIn(Vector4 backdrop, Vector4 source, float opacity)
GeneratePixelBlender("Over"); {
GeneratePixelBlender("In"); opacity = opacity.Clamp(0, 1);
GeneratePixelBlender("Out"); source.W *= opacity;
GeneratePixelBlender("Dest");
GeneratePixelBlender("DestAtop"); return In(source, backdrop, <#=blender#>(source, backdrop));
GeneratePixelBlender("DestOver"); }
GeneratePixelBlender("DestIn");
GeneratePixelBlender("DestOut"); [MethodImpl(MethodImplOptions.AggressiveInlining)]
GeneratePixelBlender("Clear"); public static Vector4 <#=blender#>DestOut(Vector4 backdrop, Vector4 source, float opacity)
GeneratePixelBlender("Xor"); {
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
#>
} return Out(source, backdrop);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 <#=blender#>Xor(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
return Xor(backdrop, source);
}
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 <#=blender#>Clear(Vector4 backdrop, Vector4 source, float opacity)
{
opacity = opacity.Clamp(0, 1);
source.W *= opacity;
return Clear(backdrop, source);
}
<# } #>
<# void GenerateGenericPixelBlender(string blender, string composer) { #>
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static TPixel <#=blender#><#=composer#><TPixel>(TPixel backdrop, TPixel source, float opacity)
where TPixel : struct, IPixel<TPixel>
{
TPixel dest = default;
dest.PackFromVector4(<#=blender#><#=composer#>(backdrop.ToVector4(),source.ToVector4(),opacity));
return dest;
}
<# } #>
<#
string[] composers = new []{
"Src",
"SrcAtop",
"SrcOver",
"SrcIn",
"SrcOut",
"Dest",
"DestAtop",
"DestOver",
"DestIn",
"DestOut",
"Clear",
"Xor",
};
string[] blenders = new []{
"Normal",
"Multiply",
"Add",
"Subtract",
"Screen",
"Darken",
"Lighten",
"Overlay",
"HardLight"
};
foreach(var blender in blenders)
{
GeneratePixelBlenders(blender);
foreach(var composer in composers)
{
GenerateGenericPixelBlender(blender,composer);
}
}
#>
}
} }

449
src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs

@ -1,194 +1,257 @@
// 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;
using System.Numerics; using System.Numerics;
using System.Runtime.CompilerServices; using System.Runtime.CompilerServices;
namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders
{ {
/// <summary> /// <summary>
/// Collection of Porter Duff alpha blending functions applying an the 'Over' composition model. /// Collection of Porter Duff alpha blending functions applying an the 'Over' composition model.
/// </summary> /// </summary>
/// <remarks> /// <remarks>
/// These functions are designed to be a general solution for all color cases, /// These functions are designed to be a general solution for all color cases,
/// that is, they take in account the alpha value of both the backdrop /// that is, they take in account the alpha value of both the backdrop
/// and source, and there's no need to alpha-premultiply neither the backdrop /// and source, and there's no need to alpha-premultiply neither the backdrop
/// nor the source. /// nor the source.
/// Note there are faster functions for when the backdrop color is known /// Note there are faster functions for when the backdrop color is known
/// to be opaque /// to be opaque
/// </remarks> /// </remarks>
internal static partial class PorterDuffFunctions internal static partial class PorterDuffFunctions
{ {
/// <summary> /// <summary>
/// Source over backdrop /// Source over backdrop
/// </summary> /// </summary>
/// <param name="backdrop">Backdrop color</param> /// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param> /// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <returns>Output color</returns>
/// <returns>Output color</returns> [MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Normal(Vector4 backdrop, Vector4 source)
public static Vector4 Normal(Vector4 backdrop, Vector4 source, float opacity) {
{ return source;
source.W *= opacity; }
return Compose(backdrop, source, source);
} /// <summary>
/// Source multiplied by backdrop
/// <summary> /// </summary>
/// Source multiplied by backdrop /// <param name="backdrop">Backdrop color</param>
/// </summary> /// <param name="source">Source color</param>
/// <param name="backdrop">Backdrop color</param> /// <returns>Output color</returns>
/// <param name="source">Source color</param> [MethodImpl(MethodImplOptions.AggressiveInlining)]
/// <param name="opacity">Opacity applied to Source Alpha</param> public static Vector4 Multiply(Vector4 backdrop, Vector4 source)
/// <returns>Output color</returns> {
[MethodImpl(MethodImplOptions.AggressiveInlining)] return backdrop * source;
public static Vector4 Multiply(Vector4 backdrop, Vector4 source, float opacity) }
{
source.W *= opacity; /// <summary>
return Compose(backdrop, source, backdrop * source); /// Source added to backdrop
} /// </summary>
/// <param name="backdrop">Backdrop color</param>
/// <summary> /// <param name="source">Source color</param>
/// Source added to backdrop /// <returns>Output color</returns>
/// </summary> [MethodImpl(MethodImplOptions.AggressiveInlining)]
/// <param name="backdrop">Backdrop color</param> public static Vector4 Add(Vector4 backdrop, Vector4 source)
/// <param name="source">Source color</param> {
/// <param name="opacity">Opacity applied to Source Alpha</param> return Vector4.Min(Vector4.One, backdrop + source);
/// <returns>Output color</returns> }
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Add(Vector4 backdrop, Vector4 source, float opacity) /// <summary>
{ /// Source subtracted from backdrop
source.W *= opacity; /// </summary>
return Compose(backdrop, source, Vector4.Min(Vector4.One, backdrop + source)); /// <param name="backdrop">Backdrop color</param>
} /// <param name="source">Source color</param>
/// <returns>Output color</returns>
/// <summary> [MethodImpl(MethodImplOptions.AggressiveInlining)]
/// Source subtracted from backdrop public static Vector4 Subtract(Vector4 backdrop, Vector4 source)
/// </summary> {
/// <param name="backdrop">Backdrop color</param> return Vector4.Max(Vector4.Zero, backdrop - source);
/// <param name="source">Source color</param> }
/// <param name="opacity">Opacity applied to Source Alpha</param>
/// <returns>Output color</returns> /// <summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// Complement of source multiplied by the complement of backdrop
public static Vector4 Subtract(Vector4 backdrop, Vector4 source, float opacity) /// </summary>
{ /// <param name="backdrop">Backdrop color</param>
source.W *= opacity; /// <param name="source">Source color</param>
return Compose(backdrop, source, Vector4.Max(Vector4.Zero, backdrop - source)); /// <returns>Output color</returns>
} [MethodImpl(MethodImplOptions.AggressiveInlining)]
public static Vector4 Screen(Vector4 backdrop, Vector4 source)
/// <summary> {
/// Complement of source multiplied by the complement of backdrop return Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source));
/// </summary> }
/// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param> /// <summary>
/// <param name="opacity">Opacity applied to Source Alpha</param> /// Per element, chooses the smallest value of source and backdrop
/// <returns>Output color</returns> /// </summary>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// <param name="backdrop">Backdrop color</param>
public static Vector4 Screen(Vector4 backdrop, Vector4 source, float opacity) /// <param name="source">Source color</param>
{ /// <returns>Output color</returns>
source.W *= opacity; [MethodImpl(MethodImplOptions.AggressiveInlining)]
return Compose(backdrop, source, Vector4.One - ((Vector4.One - backdrop) * (Vector4.One - source))); public static Vector4 Darken(Vector4 backdrop, Vector4 source)
} {
return Vector4.Min(backdrop, source);
/// <summary> }
/// Per element, chooses the smallest value of source and backdrop
/// </summary> /// <summary>
/// <param name="backdrop">Backdrop color</param> /// Per element, chooses the largest value of source and backdrop
/// <param name="source">Source color</param> /// </summary>
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="backdrop">Backdrop color</param>
/// <returns>Output color</returns> /// <param name="source">Source color</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// <returns>Output color</returns>
public static Vector4 Darken(Vector4 backdrop, Vector4 source, float opacity) [MethodImpl(MethodImplOptions.AggressiveInlining)]
{ public static Vector4 Lighten(Vector4 backdrop, Vector4 source)
source.W *= opacity; {
return Compose(backdrop, source, Vector4.Min(backdrop, source)); return Vector4.Max(backdrop, source);
} }
/// <summary> /// <summary>
/// Per element, chooses the largest value of source and backdrop /// Overlays source over backdrop
/// </summary> /// </summary>
/// <param name="backdrop">Backdrop color</param> /// <param name="backdrop">Backdrop color</param>
/// <param name="source">Source color</param> /// <param name="source">Source color</param>
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <returns>Output color</returns>
/// <returns>Output color</returns> [MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Overlay(Vector4 backdrop, Vector4 source)
public static Vector4 Lighten(Vector4 backdrop, Vector4 source, float opacity) {
{ float cr = OverlayValueFunction(backdrop.X, source.X);
source.W *= opacity; float cg = OverlayValueFunction(backdrop.Y, source.Y);
return Compose(backdrop, source, Vector4.Max(backdrop, source)); float cb = OverlayValueFunction(backdrop.Z, source.Z);
}
return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0));
/// <summary> }
/// Overlays source over backdrop
/// </summary> /// <summary>
/// <param name="backdrop">Backdrop color</param> /// Hard light effect
/// <param name="source">Source color</param> /// </summary>
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <param name="backdrop">Backdrop color</param>
/// <returns>Output color</returns> /// <param name="source">Source color</param>
[MethodImpl(MethodImplOptions.AggressiveInlining)] /// <returns>Output color</returns>
public static Vector4 Overlay(Vector4 backdrop, Vector4 source, float opacity) [MethodImpl(MethodImplOptions.AggressiveInlining)]
{ public static Vector4 HardLight(Vector4 backdrop, Vector4 source)
source.W *= opacity; {
float cr = OverlayValueFunction(backdrop.X, source.X); float cr = OverlayValueFunction(source.X, backdrop.X);
float cg = OverlayValueFunction(backdrop.Y, source.Y); float cg = OverlayValueFunction(source.Y, backdrop.Y);
float cb = OverlayValueFunction(backdrop.Z, source.Z); float cb = OverlayValueFunction(source.Z, backdrop.Z);
return Compose(backdrop, source, Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0))); return Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0));
} }
/// <summary> /// <summary>
/// Hard light effect /// Helper function for Overlay andHardLight modes
/// </summary> /// </summary>
/// <param name="backdrop">Backdrop color</param> /// <param name="backdrop">Backdrop color element</param>
/// <param name="source">Source color</param> /// <param name="source">Source color element</param>
/// <param name="opacity">Opacity applied to Source Alpha</param> /// <returns>Overlay value</returns>
/// <returns>Output color</returns> [MethodImpl(MethodImplOptions.AggressiveInlining)]
[MethodImpl(MethodImplOptions.AggressiveInlining)] private static float OverlayValueFunction(float backdrop, float source)
public static Vector4 HardLight(Vector4 backdrop, Vector4 source, float opacity) {
{ return backdrop <= 0.5f ? (2 * backdrop * source) : 1 - ((2 * (1 - source)) * (1 - backdrop));
source.W *= opacity; }
float cr = OverlayValueFunction(source.X, backdrop.X);
float cg = OverlayValueFunction(source.Y, backdrop.Y); /// <summary>
float cb = OverlayValueFunction(source.Z, backdrop.Z); /// General composition function for all modes, with a general solution for alpha channel
/// </summary>
return Compose(backdrop, source, Vector4.Min(Vector4.One, new Vector4(cr, cg, cb, 0))); /// <param name="backdrop">Original Backdrop color</param>
} /// <param name="source">Original source color</param>
/// <param name="xform">Desired transformed color, without taking Alpha channel in account</param>
/// <summary> /// <returns>The final color</returns>
/// Helper function for Overlay andHardLight modes [MethodImpl(MethodImplOptions.AggressiveInlining)]
/// </summary> private static Vector4 SrcOverReference(Vector4 backdrop, Vector4 source, Vector4 xform)
/// <param name="backdrop">Backdrop color element</param> {
/// <param name="source">Source color element</param> // calculate weights
/// <returns>Overlay value</returns> float xw = backdrop.W * source.W;
[MethodImpl(MethodImplOptions.AggressiveInlining)] float bw = backdrop.W - xw;
private static float OverlayValueFunction(float backdrop, float source) float sw = source.W - xw;
{
return backdrop <= 0.5f ? (2 * backdrop * source) : 1 - ((2 * (1 - source)) * (1 - backdrop)); // calculate final alpha
} float a = xw + bw + sw;
/// <summary> // calculate final value
/// General composition function for all modes, with a general solution for alpha channel xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
/// </summary> xform.W = a;
/// <param name="backdrop">Original Backdrop color</param>
/// <param name="source">Original source color</param> return xform;
/// <param name="xform">Desired transformed color, without taking Alpha channel in account</param> }
/// <returns>The final color</returns>
[MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Over(Vector4 dst, Vector4 src, Vector4 blend)
private static Vector4 Compose(Vector4 backdrop, Vector4 source, Vector4 xform) {
{ // calculate weights
// calculate weights float blendW = dst.W * src.W;
float xw = backdrop.W * source.W; float dstW = dst.W - blendW;
float bw = backdrop.W - xw; float srcW = src.W - blendW;
float sw = source.W - xw;
// calculate final alpha
// calculate final alpha float alpha = dstW + srcW + blendW;
float a = xw + bw + sw;
// calculate final color
// calculate final value Vector4 color = (dst * dstW) + (src * srcW) + (blend * blendW);
xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon);
xform.W = a; // unpremultiply
color /= MathF.Max(alpha, Constants.Epsilon);
return xform; color.W = alpha;
}
} return color;
}
public static Vector4 Atop(Vector4 dst, Vector4 src, Vector4 blend)
{
// calculate weights
float blendW = dst.W * src.W;
float dstW = dst.W - blendW;
// calculate final alpha
float alpha = dstW + blendW;
// calculate final color
Vector4 color = (dst * dstW) + (blend * blendW);
// unpremultiply
color /= MathF.Max(alpha, Constants.Epsilon);
color.W = alpha;
return color;
}
public static Vector4 In(Vector4 dst, Vector4 src, Vector4 blend)
{
float alpha = dst.W * src.W;
Vector4 color = src * alpha; // premultiply
color /= MathF.Max(alpha, Constants.Epsilon); // unpremultiply
color.W = alpha;
return color;
}
public static Vector4 Out(Vector4 dst, Vector4 src)
{
float alpha = (1 - dst.W) * src.W;
Vector4 color = src * alpha; // premultiply
color /= MathF.Max(alpha, Constants.Epsilon); // unpremultiply
color.W = alpha;
return color;
}
public static Vector4 Xor(Vector4 dst, Vector4 src)
{
float srcW = 1 - dst.W;
float dstW = 1 - src.W;
float alpha = (src.W * srcW) + (dst.W * dstW);
Vector4 color = (src.W * src * srcW) + (dst.W * dst * dstW);
// unpremultiply
color /= MathF.Max(alpha, Constants.Epsilon);
color.W = alpha;
return color;
}
private static Vector4 Clear(Vector4 backdrop, Vector4 source)
{
return Vector4.Zero;
}
}
} }

56
src/ImageSharp/PixelFormats/PixelColorBlendingMode.cs

@ -0,0 +1,56 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.PixelFormats
{
/// <summary>
/// Enumerates the various color blending modes.
/// </summary>
public enum PixelColorBlendingMode
{
/// <summary>
/// Default blending mode, also known as "Normal" or "Alpha Blending"
/// </summary>
Normal = 0,
/// <summary>
/// Blends the 2 values by multiplication.
/// </summary>
Multiply,
/// <summary>
/// Blends the 2 values by addition.
/// </summary>
Add,
/// <summary>
/// Blends the 2 values by subtraction.
/// </summary>
Subtract,
/// <summary>
/// Multiplies the complements of the backdrop and source values, then complements the result.
/// </summary>
Screen,
/// <summary>
/// Selects the minimum of the backdrop and source values.
/// </summary>
Darken,
/// <summary>
/// Selects the max of the backdrop and source values.
/// </summary>
Lighten,
/// <summary>
/// Multiplies or screens the values, depending on the backdrop vector values.
/// </summary>
Overlay,
/// <summary>
/// Multiplies or screens the colors, depending on the source value.
/// </summary>
HardLight,
}
}

265
src/ImageSharp/PixelFormats/PixelOperations{TPixel}.PixelBenders.cs

@ -1,50 +1,217 @@
// 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 SixLabors.ImageSharp.PixelFormats.PixelBlenders; using SixLabors.ImageSharp.PixelFormats.PixelBlenders;
namespace SixLabors.ImageSharp.PixelFormats namespace SixLabors.ImageSharp.PixelFormats
{ {
/// <content> /// <content>
/// Provides access to pixel blenders /// Provides access to pixel blenders
/// </content> /// </content>
public partial class PixelOperations<TPixel> public partial class PixelOperations<TPixel>
where TPixel : struct, IPixel<TPixel> where TPixel : struct, IPixel<TPixel>
{ {
/// <summary> /// <summary>
/// Find an instance of the pixel blender. /// Find an instance of the pixel blender.
/// </summary> /// </summary>
/// <param name="mode">The blending mode to apply</param> /// <param name="options">the blending and composition to apply</param>
/// <returns>A <see cref="PixelBlender{TPixel}"/>.</returns> /// <returns>A <see cref="PixelBlender{TPixel}"/>.</returns>
internal virtual PixelBlender<TPixel> GetPixelBlender(PixelBlenderMode mode) internal PixelBlender<TPixel> GetPixelBlender(GraphicsOptions options)
{ {
switch (mode) return this.GetPixelBlender(options.ColorBlendingMode, options.AlphaCompositionMode);
{ }
case PixelBlenderMode.Multiply: return DefaultPixelBlenders<TPixel>.Multiply.Instance;
case PixelBlenderMode.Add: return DefaultPixelBlenders<TPixel>.Add.Instance; /// <summary>
case PixelBlenderMode.Subtract: return DefaultPixelBlenders<TPixel>.Subtract.Instance; /// Find an instance of the pixel blender.
case PixelBlenderMode.Screen: return DefaultPixelBlenders<TPixel>.Screen.Instance; /// </summary>
case PixelBlenderMode.Darken: return DefaultPixelBlenders<TPixel>.Darken.Instance; /// <param name="colorMode">The color blending mode to apply</param>
case PixelBlenderMode.Lighten: return DefaultPixelBlenders<TPixel>.Lighten.Instance; /// <param name="alphaMode">The alpha composition mode to apply</param>
case PixelBlenderMode.Overlay: return DefaultPixelBlenders<TPixel>.Overlay.Instance; /// <returns>A <see cref="PixelBlender{TPixel}"/>.</returns>
case PixelBlenderMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLight.Instance; internal virtual PixelBlender<TPixel> GetPixelBlender(PixelColorBlendingMode colorMode, PixelAlphaCompositionMode alphaMode)
case PixelBlenderMode.Src: return DefaultPixelBlenders<TPixel>.Src.Instance; {
case PixelBlenderMode.Atop: return DefaultPixelBlenders<TPixel>.Atop.Instance; switch (alphaMode)
case PixelBlenderMode.Over: return DefaultPixelBlenders<TPixel>.Over.Instance; {
case PixelBlenderMode.In: return DefaultPixelBlenders<TPixel>.In.Instance; case PixelAlphaCompositionMode.Clear:
case PixelBlenderMode.Out: return DefaultPixelBlenders<TPixel>.Out.Instance; switch (colorMode)
case PixelBlenderMode.Dest: return DefaultPixelBlenders<TPixel>.Dest.Instance; {
case PixelBlenderMode.DestAtop: return DefaultPixelBlenders<TPixel>.DestAtop.Instance; case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyClear.Instance;
case PixelBlenderMode.DestOver: return DefaultPixelBlenders<TPixel>.DestOver.Instance; case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddClear.Instance;
case PixelBlenderMode.DestIn: return DefaultPixelBlenders<TPixel>.DestIn.Instance; case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractClear.Instance;
case PixelBlenderMode.DestOut: return DefaultPixelBlenders<TPixel>.DestOut.Instance; case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenClear.Instance;
case PixelBlenderMode.Clear: return DefaultPixelBlenders<TPixel>.Clear.Instance; case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenClear.Instance;
case PixelBlenderMode.Xor: return DefaultPixelBlenders<TPixel>.Xor.Instance; case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenClear.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayClear.Instance;
case PixelBlenderMode.Normal: case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightClear.Instance;
default: case PixelColorBlendingMode.Normal:
return DefaultPixelBlenders<TPixel>.Normal.Instance; default: return DefaultPixelBlenders<TPixel>.NormalClear.Instance;
} }
}
} case PixelAlphaCompositionMode.Xor:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyXor.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddXor.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractXor.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenXor.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenXor.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenXor.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayXor.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightXor.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalXor.Instance;
}
case PixelAlphaCompositionMode.Src:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrc.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrc.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrc.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrc.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrc.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrc.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrc.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrc.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalSrc.Instance;
}
case PixelAlphaCompositionMode.SrcAtop:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcAtop.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcAtop.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcAtop.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcAtop.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcAtop.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcAtop.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcAtop.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcAtop.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalSrcAtop.Instance;
}
case PixelAlphaCompositionMode.SrcIn:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcIn.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcIn.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcIn.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcIn.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcIn.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcIn.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcIn.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcIn.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalSrcIn.Instance;
}
case PixelAlphaCompositionMode.SrcOut:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcOut.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcOut.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcOut.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcOut.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcOut.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcOut.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcOut.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcOut.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalSrcOut.Instance;
}
case PixelAlphaCompositionMode.Dest:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDest.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDest.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDest.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDest.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDest.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDest.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDest.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDest.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalDest.Instance;
}
case PixelAlphaCompositionMode.DestAtop:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestAtop.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestAtop.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestAtop.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestAtop.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestAtop.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestAtop.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestAtop.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestAtop.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalDestAtop.Instance;
}
case PixelAlphaCompositionMode.DestIn:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestIn.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestIn.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestIn.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestIn.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestIn.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestIn.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestIn.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestIn.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalDestIn.Instance;
}
case PixelAlphaCompositionMode.DestOut:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestOut.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestOut.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestOut.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestOut.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestOut.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestOut.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestOut.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestOut.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalDestOut.Instance;
}
case PixelAlphaCompositionMode.DestOver:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplyDestOver.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddDestOver.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractDestOver.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenDestOver.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenDestOver.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenDestOver.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlayDestOver.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightDestOver.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalDestOver.Instance;
}
case PixelAlphaCompositionMode.SrcOver:
default:
switch (colorMode)
{
case PixelColorBlendingMode.Multiply: return DefaultPixelBlenders<TPixel>.MultiplySrcOver.Instance;
case PixelColorBlendingMode.Add: return DefaultPixelBlenders<TPixel>.AddSrcOver.Instance;
case PixelColorBlendingMode.Subtract: return DefaultPixelBlenders<TPixel>.SubtractSrcOver.Instance;
case PixelColorBlendingMode.Screen: return DefaultPixelBlenders<TPixel>.ScreenSrcOver.Instance;
case PixelColorBlendingMode.Darken: return DefaultPixelBlenders<TPixel>.DarkenSrcOver.Instance;
case PixelColorBlendingMode.Lighten: return DefaultPixelBlenders<TPixel>.LightenSrcOver.Instance;
case PixelColorBlendingMode.Overlay: return DefaultPixelBlenders<TPixel>.OverlaySrcOver.Instance;
case PixelColorBlendingMode.HardLight: return DefaultPixelBlenders<TPixel>.HardLightSrcOver.Instance;
case PixelColorBlendingMode.Normal:
default: return DefaultPixelBlenders<TPixel>.NormalSrcOver.Instance;
}
}
}
}
} }

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

Loading…
Cancel
Save