From 43be72d777c8a9a0487af02b188cc39cc80c7fb1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 27 Nov 2017 01:22:16 +1100 Subject: [PATCH 001/185] Normalize namespace --- .../ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs | 3 +-- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs | 2 +- .../Conversion/ColorSpaceConverter.CieLchuv.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs | 3 +-- .../ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs | 6 +----- .../ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs | 3 +-- .../ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs | 2 +- .../Conversion/ColorSpaceConverter.HunterLab.cs | 2 +- .../Conversion/ColorSpaceConverter.LinearRgb.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs | 2 +- .../ColorSpaces/Conversion/ColorSpaceConverter.cs | 3 +-- .../{CieLch => }/CIeLchToCieLabConverter.cs | 2 +- .../{CieLch => }/CieLabToCieLchConverter.cs | 2 +- .../{CieLab => }/CieLabToCieXyzConverter.cs | 2 +- .../{CieLchuv => }/CieLchuvToCieLuvConverter.cs | 2 +- .../{CieLchuv => }/CieLuvToCieLchuvConverter.cs | 2 +- .../{CieLuv => }/CieLuvToCieXyzConverter.cs | 2 +- .../{CieXyy => }/CieXyzAndCieXyyConverter.cs | 2 +- .../{HunterLab => }/CieXyzAndHunterLabConverterBase.cs | 2 +- .../Implementation/{Lms => }/CieXyzAndLmsConverter.cs | 8 ++++---- .../{CieLab => }/CieXyzToCieLabConverter.cs | 2 +- .../{CieLuv => }/CieXyzToCieLuvConverter.cs | 2 +- .../{HunterLab => }/CieXyzToHunterLabConverter.cs | 2 +- .../{Rgb => }/CieXyzToLinearRgbConverter.cs | 2 +- .../Implementation/{Cmyk => }/CmykAndRgbConverter.cs | 2 +- .../Implementation/{Rgb => }/GammaCompanding.cs | 2 +- .../Implementation/{Hsl => }/HslAndRgbConverter.cs | 2 +- .../Implementation/{Hsv => }/HsvAndRgbConverter.cs | 2 +- .../{HunterLab => }/HunterLabToCieXyzConverter.cs | 2 +- .../Conversion/Implementation/{Rgb => }/LCompanding.cs | 2 +- .../{Rgb => }/LinearRgbAndCieXyzConverterBase.cs | 2 +- .../{Rgb => }/LinearRgbToCieXyzConverter.cs | 2 +- .../Implementation/{Rgb => }/LinearRgbToRgbConverter.cs | 2 +- .../Implementation/{Lms => }/LmsAdaptationMatrix.cs | 2 +- .../{Rgb => }/RGBPrimariesChromaticityCoordinates.cs | 2 +- .../Implementation/{Rgb => }/Rec2020Companding.cs | 2 +- .../Implementation/{Rgb => }/Rec709Companding.cs | 2 +- .../Implementation/{Rgb => }/RgbToLinearRgbConverter.cs | 2 +- .../Implementation/{Rgb => }/RgbWorkingSpace.cs | 6 +++--- .../Conversion/Implementation/{Rgb => }/SRgbCompanding.cs | 2 +- .../Implementation/{YCbCr => }/YCbCrAndRgbConverter.cs | 3 +-- .../ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs | 4 ++-- src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs | 2 +- src/ImageSharp/ColorSpaces/Lms.cs | 4 ++-- src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs | 2 +- .../Colorspaces/ColorConverterAdaptTest.cs | 2 +- 50 files changed, 57 insertions(+), 66 deletions(-) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{CieLch => }/CIeLchToCieLabConverter.cs (97%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{CieLch => }/CieLabToCieLchConverter.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{CieLab => }/CieLabToCieXyzConverter.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{CieLchuv => }/CieLchuvToCieLuvConverter.cs (97%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{CieLchuv => }/CieLuvToCieLchuvConverter.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{CieLuv => }/CieLuvToCieXyzConverter.cs (99%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{CieXyy => }/CieXyzAndCieXyyConverter.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{HunterLab => }/CieXyzAndHunterLabConverterBase.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Lms => }/CieXyzAndLmsConverter.cs (91%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{CieLab => }/CieXyzToCieLabConverter.cs (99%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{CieLuv => }/CieXyzToCieLuvConverter.cs (99%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{HunterLab => }/CieXyzToHunterLabConverter.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/CieXyzToLinearRgbConverter.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Cmyk => }/CmykAndRgbConverter.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/GammaCompanding.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Hsl => }/HslAndRgbConverter.cs (99%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Hsv => }/HsvAndRgbConverter.cs (99%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{HunterLab => }/HunterLabToCieXyzConverter.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/LCompanding.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/LinearRgbAndCieXyzConverterBase.cs (99%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/LinearRgbToCieXyzConverter.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/LinearRgbToRgbConverter.cs (97%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Lms => }/LmsAdaptationMatrix.cs (99%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/RGBPrimariesChromaticityCoordinates.cs (99%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/Rec2020Companding.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/Rec709Companding.cs (97%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/RgbToLinearRgbConverter.cs (97%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/RgbWorkingSpace.cs (97%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{Rgb => }/SRgbCompanding.cs (98%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{YCbCr => }/YCbCrAndRgbConverter.cs (96%) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index 80f9e6789b..2052b083c9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -3,7 +3,7 @@ using System; using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 9268f3a70c..ddfbc2ff7a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -2,8 +2,7 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 13dae4b174..9854d8e1b7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index cef63e73d2..0186ba7c28 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index 04aee4897b..498f0cc9d0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -2,8 +2,7 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvColorSapce; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index 31e1e218ea..ce8b85c4c3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieXyyColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index e6847beafe..4dfa4298b1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -1,11 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColorSapce; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index 637c121ea0..8cd4a13a77 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -1,8 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CmykColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index dbc31c52b8..35d784c4a4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HslColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index 640461505b..e47ab45ef2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HsvColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index f5ab4d645c..6761390524 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index 7b45704afc..6258e6e18c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index de13b97eb8..5b3613adbf 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 8da7dcb7ef..67b4472ab7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.YCbCrColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index f86f505387..dab06e1ea9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -2,8 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs similarity index 97% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs index 35fae30e83..a9be6d47af 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs index aa4614f9ca..6bfb9ae522 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLch/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs index 0a5ae3627e..60e8924739 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs similarity index 97% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs index fc6554a905..d73f1af394 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs index f0d7a80a22..e201cb143b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuv/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLchuvColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs similarity index 99% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs index 50e8335ed6..f74eb93637 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieLuvToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs index 64fc84b1d4..9bdfdd8dd1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyy/CieXyzAndCieXyyConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieXyyColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between CIE XYZ and CIE xyY diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndHunterLabConverterBase.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndHunterLabConverterBase.cs index 85b0efd16a..cc2068ffa2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzAndHunterLabConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndHunterLabConverterBase.cs @@ -3,7 +3,7 @@ using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// The base class for converting between and color spaces. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs similarity index 91% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/CieXyzAndLmsConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs index 780c9e5a6e..e0d22a6310 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/CieXyzAndLmsConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs @@ -3,9 +3,8 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between CIE XYZ and LMS @@ -52,6 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSap [MethodImpl(MethodImplOptions.AggressiveInlining)] get => this.transformationMatrix; + [MethodImpl(MethodImplOptions.AggressiveInlining)] set { this.transformationMatrix = value; @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSap { DebugGuard.NotNull(input, nameof(input)); - Vector3 vector = Vector3.Transform(input.Vector, this.transformationMatrix); + var vector = Vector3.Transform(input.Vector, this.transformationMatrix); return new Lms(vector); } @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSap { DebugGuard.NotNull(input, nameof(input)); - Vector3 vector = Vector3.Transform(input.Vector, this.inverseTransformationMatrix); + var vector = Vector3.Transform(input.Vector, this.inverseTransformationMatrix); return new CieXyz(vector); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs similarity index 99% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs index 22308260c2..a22e1452fc 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLab/CieXyzToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLabColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs similarity index 99% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs index 709d8d426e..2379c066b2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuv/CieXyzToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CieLuvColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Converts from to . diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs index 7faf03c9a1..4fd0645038 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between CieXyz and HunterLab diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/CieXyzToLinearRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs index fd76a30fb8..a45f11c0ec 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs @@ -3,7 +3,7 @@ using System.Numerics; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between CieXyz and LinearRgb diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Cmyk/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Cmyk/CmykAndRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs index 404bc811ff..343bbf99bb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Cmyk/CmykAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.CmykColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between CMYK and Rgb diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/GammaCompanding.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs index 21a80225ee..aadb0d3426 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/GammaCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Implements gamma companding diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs similarity index 99% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs index 3de3baddd3..441d1fc236 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsl/HslAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HslColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between HSL and Rgb diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsv/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs similarity index 99% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsv/HsvAndRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs index 6219533ca5..953795a528 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Hsv/HsvAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HsvColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between HSV and Rgb diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs index 7e7c536e3f..b391cdb26f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLab/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs @@ -5,7 +5,7 @@ using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.HunterLabColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between HunterLab and CieXyz diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LCompanding.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs index 132861b476..4af7d96ff9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Implements L* companding diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs similarity index 99% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbAndCieXyzConverterBase.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs index 2ec79b353b..962c45ab41 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs @@ -3,7 +3,7 @@ using System.Numerics; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Provides base methods for converting between Rgb and CieXyz color spaces. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToCieXyzConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs index 19d4130373..351df1ff8e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs @@ -3,7 +3,7 @@ using System.Numerics; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between LinearRgb and CieXyz diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs similarity index 97% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs index 29ea0f3148..364fdead67 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs @@ -3,7 +3,7 @@ using System.Numerics; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between LinearRgb and Rgb diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/LmsAdaptationMatrix.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs similarity index 99% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/LmsAdaptationMatrix.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs index 1bd0c4ad50..a11b31da6b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Lms/LmsAdaptationMatrix.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs @@ -4,7 +4,7 @@ using System.Numerics; // ReSharper disable InconsistentNaming -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// AdaptionMatrix3X3 used for transformation from XYZ to LMS, defining the cone response domain. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs similarity index 99% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs index d279aba850..332db5649c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs @@ -3,7 +3,7 @@ using System; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Represents the chromaticity coordinates of RGB primaries. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec2020Companding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec2020Companding.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs index 11761f0e4d..86f07643c3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec2020Companding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Implements Rec. 2020 companding function (for 12-bits). diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs similarity index 97% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec709Companding.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs index ccda6bf521..a75eedc0b9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/Rec709Companding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Implements the Rec. 709 companding function diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs similarity index 97% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbToLinearRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs index e40ecc192e..3bc906ced9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs @@ -3,7 +3,7 @@ using System.Numerics; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between Rgb and LinearRgb diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs similarity index 97% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs index 8a2c66a80c..19c0ad0ba8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Trivial implementation of @@ -73,9 +73,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSap /// public override bool Equals(object obj) { - if (obj is RgbWorkingSpace) + if (obj is RgbWorkingSpace space) { - return this.Equals((RgbWorkingSpace)obj); + return this.Equals(space); } return false; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs similarity index 98% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/SRgbCompanding.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs index ce8ea7c6e5..e3568deb05 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rgb/SRgbCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Implements sRGB companding diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCr/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs similarity index 96% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCr/YCbCrAndRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs index f552acbb48..2998f6c56b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCr/YCbCrAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs @@ -4,9 +4,8 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.YCbCrColorSapce +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Color converter between YCbCr and Rgb diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index 6edae93017..3564bc1de3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -3,7 +3,7 @@ using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint); Lms targetWhitePointLms = this.converter.Convert(targetWhitePoint); - var vector = new Vector3(targetWhitePointLms.L / sourceWhitePointLms.L, targetWhitePointLms.M / sourceWhitePointLms.M, targetWhitePointLms.S / sourceWhitePointLms.S); + Vector3 vector = targetWhitePointLms.Vector / sourceWhitePointLms.Vector; var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.Vector)); return this.converter.Convert(targetColorLms); diff --git a/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs index 156e94ed3c..d1ebe145ea 100644 --- a/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces { diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 82c291de3d..40dce5207c 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -149,9 +149,9 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public override bool Equals(object obj) { - if (obj is Lms) + if (obj is Lms lms) { - return this.Equals((Lms)obj); + return this.Equals(lms); } return false; diff --git a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs index 098ca9a4a4..08c83d674e 100644 --- a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs +++ b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.ColorSpaces diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs index 87dc59907b..f25ef92ffc 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs @@ -4,7 +4,7 @@ using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.LmsColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; using Xunit; namespace SixLabors.ImageSharp.Tests.Colorspaces From 3551e3fb9447b48559ab6bf72bf63df41ffec2ee Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 27 Nov 2017 08:33:59 +1100 Subject: [PATCH 002/185] Cleanup + obvious perf improvements --- .../Implementation/CIeLchToCieLabConverter.cs | 1 - .../Implementation/CieLabToCieLchConverter.cs | 1 - .../Implementation/CieLabToCieXyzConverter.cs | 14 +++++--------- .../Implementation/CieLchuvToCieLuvConverter.cs | 1 - .../Implementation/CieLuvToCieLchuvConverter.cs | 1 - .../Implementation/CieLuvToCieXyzConverter.cs | 1 - .../Implementation/CieXyzAndCieXyyConverter.cs | 1 - .../Implementation/CieXyzToCieLabConverter.cs | 1 - .../Implementation/CieXyzToCieLuvConverter.cs | 1 - .../Implementation/CieXyzToHunterLabConverter.cs | 1 - .../Implementation/CieXyzToLinearRgbConverter.cs | 2 +- .../Implementation/HslAndRgbConverter.cs | 1 - .../Implementation/HunterLabToCieXyzConverter.cs | 1 - .../LinearRgbAndCieXyzConverterBase.cs | 7 +++---- .../Implementation/LinearRgbToCieXyzConverter.cs | 2 +- .../RGBPrimariesChromaticityCoordinates.cs | 16 ++++++++-------- .../Colorspaces/CieXyzAndCieLabConversionTest.cs | 12 ++++++------ 17 files changed, 24 insertions(+), 40 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs index a9be6d47af..3581c5d355 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs index 6bfb9ae522..c6408b8664 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs index 60e8924739..d1670c321d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Numerics; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation @@ -30,18 +31,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? MathF.Pow((l + 16F) / 116F, 3F) : l / CieConstants.Kappa; float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa; - float wx = input.WhitePoint.X, wy = input.WhitePoint.Y, wz = input.WhitePoint.Z; + var wxyz = new Vector3(input.WhitePoint.X, input.WhitePoint.Y, input.WhitePoint.Z); // Avoids XYZ coordinates out range (restricted by 0 and XYZ reference white) - xr = xr.Clamp(0, 1F); - yr = yr.Clamp(0, 1F); - zr = zr.Clamp(0, 1F); + var xyzr = Vector3.Clamp(new Vector3(xr, yr, zr), Vector3.Zero, Vector3.One); - float x = xr * wx; - float y = yr * wy; - float z = zr * wz; - - return new CieXyz(x, y, z); + Vector3 xyz = xyzr * wxyz; + return new CieXyz(xyz); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs index d73f1af394..406cbb91bf 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs index e201cb143b..b9e9107635 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs index f74eb93637..179c6fae48 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs index 9bdfdd8dd1..e4ce1edcba 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs index a22e1452fc..288b50e12e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs index 2379c066b2..5f395eb0ce 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs index 4fd0645038..e6fb663abf 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs index a45f11c0ec..5c18cb8e12 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation DebugGuard.NotNull(input, nameof(input)); Matrix4x4.Invert(this.conversionMatrix, out Matrix4x4 inverted); - Vector3 vector = Vector3.Transform(input.Vector, inverted); + var vector = Vector3.Transform(input.Vector, inverted); return new LinearRgb(vector, this.TargetWorkingSpace); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs index 441d1fc236..4703d35518 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs index b391cdb26f..6531ffd24a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.ColorSpaces; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs index 962c45ab41..3ba0761c95 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation const float Yb = 1; float mZb = (1 - xb - yb) / yb; - Matrix4x4 xyzMatrix = new Matrix4x4 + var xyzMatrix = new Matrix4x4 { M11 = mXr, M21 = mXg, M31 = mXb, M12 = Yr, M22 = Yg, M32 = Yb, @@ -48,10 +48,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation M44 = 1F }; - Matrix4x4 inverseXyzMatrix; - Matrix4x4.Invert(xyzMatrix, out inverseXyzMatrix); + Matrix4x4.Invert(xyzMatrix, out var inverseXyzMatrix); - Vector3 vector = Vector3.Transform(workingSpace.WhitePoint.Vector, inverseXyzMatrix); + var vector = Vector3.Transform(workingSpace.WhitePoint.Vector, inverseXyzMatrix); // Use transposed Rows/Coloumns // TODO: Is there a built in method for this multiplication? diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs index 351df1ff8e..cac188853d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation DebugGuard.NotNull(input, nameof(input)); Guard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); - Vector3 vector = Vector3.Transform(input.Vector, this.conversionMatrix); + var vector = Vector3.Transform(input.Vector, this.conversionMatrix); return new CieXyz(vector); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs index 332db5649c..be199a9309 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs @@ -40,13 +40,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public CieXyChromaticityCoordinates B { get; } /// - /// Compares two objects for equality. + /// Compares two objects for equality. /// /// - /// The on the left side of the operand. + /// The on the left side of the operand. /// /// - /// The on the right side of the operand. + /// The on the right side of the operand. /// /// /// True if the current left is equal to the parameter; otherwise, false. @@ -57,13 +57,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation } /// - /// Compares two objects for inequality + /// Compares two objects for inequality /// /// - /// The on the left side of the operand. + /// The on the left side of the operand. /// /// - /// The on the right side of the operand. + /// The on the right side of the operand. /// /// /// True if the current left is unequal to the parameter; otherwise, false. @@ -76,9 +76,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public override bool Equals(object obj) { - if (obj is RgbPrimariesChromaticityCoordinates) + if (obj is RgbPrimariesChromaticityCoordinates coordinates) { - return this.Equals((RgbPrimariesChromaticityCoordinates)obj); + return this.Equals(coordinates); } return false; diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs index 76d76f236c..1be3ac9713 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs @@ -34,11 +34,11 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces public void Convert_Lab_to_Xyz(float l, float a, float b, float x, float y, float z) { // Arrange - CieLab input = new CieLab(l, a, b, Illuminants.D65); - ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var input = new CieLab(l, a, b, Illuminants.D65); + var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; // Act - CieXyz output = converter.ToCieXyz(input); + var output = converter.ToCieXyz(input); // Assert Assert.Equal(x, output.X, FloatRoundingComparer); @@ -59,11 +59,11 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces public void Convert_Xyz_to_Lab(float x, float y, float z, float l, float a, float b) { // Arrange - CieXyz input = new CieXyz(x, y, z); - ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var input = new CieXyz(x, y, z); + var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; // Act - CieLab output = converter.ToCieLab(input); + var output = converter.ToCieLab(input); // Assert Assert.Equal(l, output.L, FloatRoundingComparer); From 19be80e5dde08de3ae365337826342d70d39b6ed Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 20 Dec 2017 17:30:25 +1100 Subject: [PATCH 003/185] Use SIMD for CMYK->RGB and vice versa --- .../Implementation/CmykAndRgbConverter.cs | 24 +++++++++---------- 1 file changed, 11 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs index 343bbf99bb..f674d9444e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces; @@ -16,35 +17,32 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb Convert(Cmyk input) { - float r = (1F - input.C) * (1F - input.K); - float g = (1F - input.M) * (1F - input.K); - float b = (1F - input.Y) * (1F - input.K); + DebugGuard.NotNull(input, nameof(input)); - return new Rgb(r, g, b); + Vector3 rgb = (Vector3.One - new Vector3(input.C, input.M, input.Y)) * (Vector3.One - new Vector3(input.K)); + return new Rgb(rgb); } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cmyk Convert(Rgb input) { + DebugGuard.NotNull(input, nameof(input)); + // To CMYK - float c = 1F - input.R; - float m = 1F - input.G; - float y = 1F - input.B; + Vector3 cmy = Vector3.One - input.Vector; // To CMYK - float k = MathF.Min(c, MathF.Min(m, y)); + var k = new Vector3(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z))); - if (MathF.Abs(k - 1F) < Constants.Epsilon) + if (MathF.Abs(k.X - 1F) < Constants.Epsilon) { return new Cmyk(0, 0, 0, 1F); } - c = (c - k) / (1F - k); - m = (m - k) / (1F - k); - y = (y - k) / (1F - k); + cmy = (cmy - k) / (Vector3.One - k); - return new Cmyk(c, m, y, k); + return new Cmyk(cmy.X, cmy.Y, cmy.Z, k.X); } } } \ No newline at end of file From dd63a0a704efa229961e7cae636a0bd79b966256 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 20 Dec 2017 17:30:34 +1100 Subject: [PATCH 004/185] More cleanup --- .../Conversion/ColorSpaceConverter.Adapt.cs | 67 +++++++------------ .../Conversion/ColorSpaceConverter.CieLab.cs | 25 ++++--- .../Conversion/ColorSpaceConverter.CieLch.cs | 24 +++---- .../ColorSpaceConverter.CieLchuv.cs | 24 +++---- .../Conversion/ColorSpaceConverter.Hsl.cs | 1 - .../Conversion/ColorSpaceConverter.Hsv.cs | 1 - .../Conversion/ColorSpaceConverter.Lms.cs | 2 - .../Conversion/ColorSpaceConverter.Rgb.cs | 6 +- .../Conversion/IChromaticAdaptation.cs | 2 - .../Implementation/CieXyzToCieLuvConverter.cs | 1 + .../CieXyzToLinearRgbConverter.cs | 10 ++- .../Implementation/GammaCompanding.cs | 7 +- .../LinearRgbAndCieXyzConverterBase.cs | 2 +- .../LinearRgbToCieXyzConverter.cs | 2 +- .../Conversion/VonKriesChromaticAdaptation.cs | 1 - .../Colorspaces/RgbAndCmykConversionTest.cs | 8 +-- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 6 +- 17 files changed, 87 insertions(+), 102 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index 2052b083c9..0f62046a64 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; -using SixLabors.ImageSharp.ColorSpaces; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -23,11 +23,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); Guard.NotNull(sourceWhitePoint, nameof(sourceWhitePoint)); - - if (!this.IsChromaticAdaptationPerformed) - { - throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); - } + this.CheckChromaticAdaptation(); return this.ChromaticAdaptation.Transform(color, sourceWhitePoint, this.WhitePoint); } @@ -40,18 +36,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLab Adapt(CieLab color) { Guard.NotNull(color, nameof(color)); - - if (!this.IsChromaticAdaptationPerformed) - { - throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); - } + this.CheckChromaticAdaptation(); if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) { return color; } - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -63,18 +55,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLch Adapt(CieLch color) { Guard.NotNull(color, nameof(color)); - - if (!this.IsChromaticAdaptationPerformed) - { - throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); - } + this.CheckChromaticAdaptation(); if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) { return color; } - CieLab labColor = this.ToCieLab(color); + var labColor = this.ToCieLab(color); return this.ToCieLch(labColor); } @@ -86,18 +74,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLchuv Adapt(CieLchuv color) { Guard.NotNull(color, nameof(color)); - - if (!this.IsChromaticAdaptationPerformed) - { - throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); - } + this.CheckChromaticAdaptation(); if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) { return color; } - CieLuv luvColor = this.ToCieLuv(color); + var luvColor = this.ToCieLuv(color); return this.ToCieLchuv(luvColor); } @@ -109,18 +93,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLuv Adapt(CieLuv color) { Guard.NotNull(color, nameof(color)); - - if (!this.IsChromaticAdaptationPerformed) - { - throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); - } + this.CheckChromaticAdaptation(); if (color.WhitePoint.Equals(this.TargetLuvWhitePoint)) { return color; } - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLuv(xyzColor); } @@ -132,18 +112,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public HunterLab Adapt(HunterLab color) { Guard.NotNull(color, nameof(color)); - - if (!this.IsChromaticAdaptationPerformed) - { - throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); - } + this.CheckChromaticAdaptation(); if (color.WhitePoint.Equals(this.TargetHunterLabWhitePoint)) { return color; } - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } @@ -155,11 +131,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public LinearRgb Adapt(LinearRgb color) { Guard.NotNull(color, nameof(color)); - - if (!this.IsChromaticAdaptationPerformed) - { - throw new InvalidOperationException("Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."); - } + this.CheckChromaticAdaptation(); if (color.WorkingSpace.Equals(this.TargetRgbWorkingSpace)) { @@ -187,9 +159,20 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - LinearRgb linearInput = this.ToLinearRgb(color); + var linearInput = this.ToLinearRgb(color); LinearRgb linearOutput = this.Adapt(linearInput); return this.ToRgb(linearOutput); } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private void CheckChromaticAdaptation() + { + const string NoAdapterMessage = "Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."; + + if (!this.IsChromaticAdaptationPerformed) + { + throw new InvalidOperationException(NoAdapterMessage); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index ddfbc2ff7a..2720b81fe1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -46,7 +45,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -59,7 +58,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -72,7 +71,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -91,7 +90,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion : color; // Conversion - CieXyzToCieLabConverter converter = new CieXyzToCieLabConverter(this.TargetLabWhitePoint); + var converter = new CieXyzToCieLabConverter(this.TargetLabWhitePoint); return converter.Convert(adapted); } @@ -104,7 +103,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -117,7 +116,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -130,7 +129,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -143,7 +142,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -156,7 +155,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -169,7 +168,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -182,7 +181,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } @@ -195,7 +194,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 9854d8e1b7..ad0d4e311e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieLab labColor = this.ToCieLab(color); + var labColor = this.ToCieLab(color); return this.ToCieLch(labColor); } @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -144,7 +144,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } @@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 0186ba7c28..36e504fb1f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieLab labColor = this.ToCieLab(color); + var labColor = this.ToCieLab(color); return this.ToCieLchuv(labColor); } @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -144,7 +144,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } @@ -183,7 +183,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - CieXyz xyzColor = this.ToCieXyz(color); + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index 35d784c4a4..7099d98e40 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index e47ab45ef2..b0099977ca 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index ac3adee639..872b792961 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index 5b3613adbf..b0d57f68be 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -181,11 +181,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion Guard.NotNull(color, nameof(color)); // Conversion - Rgb rgb = YCbCrAndRgbConverter.Convert(color); - - // Adaptation - // TODO: Check this! - return rgb.WorkingSpace.Equals(this.TargetRgbWorkingSpace) ? rgb : this.Adapt(rgb); + return YCbCrAndRgbConverter.Convert(color); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs index c5d91f9a05..3e78d3a919 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces; - namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs index 5f395eb0ce..be4c5b04c1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs @@ -91,6 +91,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The whitepoint /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float ComputeVp(CieXyz input) { return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs index 5c18cb8e12..449afcc608 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Numerics; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { @@ -15,6 +16,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Initializes a new instance of the class. /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzToLinearRgbConverter() : this(Rgb.DefaultWorkingSpace) { @@ -24,6 +26,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Initializes a new instance of the class. /// /// The target working space. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzToLinearRgbConverter(IRgbWorkingSpace workingSpace) { this.TargetWorkingSpace = workingSpace; @@ -33,9 +36,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Gets the target working space /// - public IRgbWorkingSpace TargetWorkingSpace { get; } + public IRgbWorkingSpace TargetWorkingSpace + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + } /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public LinearRgb Convert(CieXyz input) { DebugGuard.NotNull(input, nameof(input)); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs index aadb0d3426..3bea562ecb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs @@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Initializes a new instance of the class. /// /// The gamma value. + [MethodImpl(MethodImplOptions.AggressiveInlining)] public GammaCompanding(float gamma) { this.Gamma = gamma; @@ -27,7 +28,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Gets the gamma value /// - public float Gamma { get; } + public float Gamma + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get; + } /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs index 3ba0761c95..2b21a604f4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation M44 = 1F }; - Matrix4x4.Invert(xyzMatrix, out var inverseXyzMatrix); + Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix); var vector = Vector3.Transform(workingSpace.WhitePoint.Vector, inverseXyzMatrix); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs index cac188853d..449b3b37b8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public CieXyz Convert(LinearRgb input) { DebugGuard.NotNull(input, nameof(input)); - Guard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); + DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); var vector = Vector3.Transform(input.Vector, this.conversionMatrix); return new CieXyz(vector); diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index 3564bc1de3..20f75f1ae2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs index 6c3d579b4e..bc4cb11069 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs @@ -32,10 +32,10 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces public void Convert_Cmyk_To_Rgb(float c, float m, float y, float k, float r, float g, float b) { // Arrange - Cmyk input = new Cmyk(c, m, y, k); + var input = new Cmyk(c, m, y, k); // Act - Rgb output = Converter.ToRgb(input); + var output = Converter.ToRgb(input); // Assert Assert.Equal(Rgb.DefaultWorkingSpace, output.WorkingSpace); @@ -54,10 +54,10 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces public void Convert_Rgb_To_Cmyk(float r, float g, float b, float c, float m, float y, float k) { // Arrange - Rgb input = new Rgb(r, g, b); + var input = new Rgb(r, g, b); // Act - Cmyk output = Converter.ToCmyk(input); + var output = Converter.ToCmyk(input); // Assert Assert.Equal(c, output.C, FloatRoundingComparer); diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 2f45e4c83a..eb60aa5fe4 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -17,9 +17,9 @@ - - - + + + From 012d1ebddd3f1aca3b49b98b97e4805391077198 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 21 Dec 2017 09:33:19 +1100 Subject: [PATCH 005/185] Update Colorful and add Pow benchmark --- tests/ImageSharp.Benchmarks/General/Pow.cs | 40 +++++++++++++++++++ .../ImageSharp.Benchmarks.csproj | 2 +- 2 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 tests/ImageSharp.Benchmarks/General/Pow.cs diff --git a/tests/ImageSharp.Benchmarks/General/Pow.cs b/tests/ImageSharp.Benchmarks/General/Pow.cs new file mode 100644 index 0000000000..325bd9d20e --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Pow.cs @@ -0,0 +1,40 @@ +using System; +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General +{ + public class Pow + { + [Params(-1.333F, 1.333F)] + public float X { get; set; } + + + [Benchmark(Baseline = true, Description = "Math.Pow 2")] + public float MathPow() + { + float x = this.X; + return (float)Math.Pow(x, 2); + } + + [Benchmark(Description = "Pow x2")] + public float PowMult() + { + float x = this.X; + return x * x; + } + + [Benchmark(Description = "Math.Pow 3")] + public float MathPow3() + { + float x = this.X; + return (float)Math.Pow(x, 3); + } + + [Benchmark(Description = "Pow x3")] + public float PowMult3() + { + float x = this.X; + return x * x * x; + } + } +} diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 417e849be1..bf546c91b1 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -15,7 +15,7 @@ - + From 2f9c2abd212906f3450f3216167ea21a363d6118 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 1 Mar 2018 23:44:32 +1100 Subject: [PATCH 006/185] Faster Pow functions --- .../Implementation/CieLabToCieXyzConverter.cs | 6 +-- .../Implementation/CieLuvToCieXyzConverter.cs | 2 +- .../HunterLabToCieXyzConverter.cs | 2 +- .../Conversion/Implementation/LCompanding.cs | 2 +- src/ImageSharp/Common/Helpers/ImageMaths.cs | 32 +++++++++------ .../ImageSharp.Benchmarks.csproj | 2 +- .../Colorspaces/ColorSpaceEqualityTests.cs | 3 +- .../Helpers/ImageMathsTests.cs | 39 +++++++++++++++++++ .../TestUtilities/ApproximateFloatComparer.cs | 2 +- 9 files changed, 69 insertions(+), 21 deletions(-) create mode 100644 tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs index d1670c321d..d2595db282 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs @@ -24,11 +24,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float fx = (a / 500F) + fy; float fz = fy - (b / 200F); - float fx3 = MathF.Pow(fx, 3F); - float fz3 = MathF.Pow(fz, 3F); + float fx3 = ImageMaths.Pow3(fx); + float fz3 = ImageMaths.Pow3(fz); float xr = fx3 > CieConstants.Epsilon ? fx3 : ((116F * fx) - 16F) / CieConstants.Kappa; - float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? MathF.Pow((l + 16F) / 116F, 3F) : l / CieConstants.Kappa; + float yr = l > CieConstants.Kappa * CieConstants.Epsilon ? ImageMaths.Pow3((l + 16F) / 116F) : l / CieConstants.Kappa; float zr = fz3 > CieConstants.Epsilon ? fz3 : ((116F * fz) - 16F) / CieConstants.Kappa; var wxyz = new Vector3(input.WhitePoint.X, input.WhitePoint.Y, input.WhitePoint.Z); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs index 179c6fae48..f26aeacec0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float v0 = ComputeV0(input.WhitePoint); float y = l > CieConstants.Kappa * CieConstants.Epsilon - ? MathF.Pow((l + 16) / 116, 3) + ? ImageMaths.Pow3((l + 16) / 116) : l / CieConstants.Kappa; float a = ((52 * l / (u + (13 * l * u0))) - 1) / 3; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs index 6531ffd24a..9eeffd3095 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float ka = ComputeKa(input.WhitePoint); float kb = ComputeKb(input.WhitePoint); - float y = MathF.Pow(l / 100F, 2) * yn; + float y = ImageMaths.Pow2(l / 100F) * yn; float x = (((a / ka) * MathF.Sqrt(y / yn)) + (y / yn)) * xn; float z = (((b / kb) * MathF.Sqrt(y / yn)) - (y / yn)) * (-zn); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs index 4af7d96ff9..9099d6bedc 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public float Expand(float channel) { - return channel <= 0.08 ? 100 * channel / CieConstants.Kappa : MathF.Pow((channel + 0.16F) / 1.16F, 3); + return channel <= 0.08 ? 100 * channel / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F); } /// diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 75c9190d24..3167a42c89 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -29,6 +29,22 @@ namespace SixLabors.ImageSharp return (x ^ y) - y; } + /// + /// Returns a specified number raised to the power of 2 + /// + /// A single-precision floating-point number + /// The number raised to the power of 2. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Pow2(float x) => x * x; + + /// + /// Returns a specified number raised to the power of 3 + /// + /// A single-precision floating-point number + /// The number raised to the power of 3. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static float Pow3(float x) => x * x * x; + /// /// Returns how many bits are required to store the specified number of colors. /// Performs a Log2() on the value. @@ -38,10 +54,7 @@ namespace SixLabors.ImageSharp /// The /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetBitsNeededForColorDepth(int colors) - { - return (int)Math.Ceiling(Math.Log(colors, 2)); - } + public static int GetBitsNeededForColorDepth(int colors) => (int)Math.Ceiling(Math.Log(colors, 2)); /// /// Implementation of 1D Gaussian G(x) function @@ -56,7 +69,7 @@ namespace SixLabors.ImageSharp float denominator = MathF.Sqrt(2 * MathF.PI) * sigma; float exponentNumerator = -x * x; - float exponentDenominator = (float)(2 * Math.Pow(sigma, 2)); + float exponentDenominator = 2 * Pow2(sigma); float left = Numerator / denominator; float right = MathF.Exp(exponentNumerator / exponentDenominator); @@ -98,14 +111,12 @@ namespace SixLabors.ImageSharp [MethodImpl(MethodImplOptions.AggressiveInlining)] public static float GetBcValue(float x, float b, float c) { - float temp; - if (x < 0F) { x = -x; } - temp = x * x; + float temp = x * x; if (x < 1F) { x = ((12 - (9 * b) - (6 * c)) * (x * temp)) + ((-18 + (12 * b) + (6 * c)) * temp) + (6 - (2 * b)); @@ -134,10 +145,7 @@ namespace SixLabors.ImageSharp /// The bounding . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) - { - return new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); - } + public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) => new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); /// /// Finds the bounding rectangle based on the first instance of any color component other diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 4e17768162..ceec8f6fb2 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -18,7 +18,7 @@ - + diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs index f0ac56f4f1..1d65e7fc71 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs @@ -9,6 +9,7 @@ using SixLabors.ImageSharp.ColorSpaces; using Xunit; // ReSharper disable InconsistentNaming +// TODO: This needs to be refactored so that it uses a serializable type once the colorspace code is public namespace SixLabors.ImageSharp.Tests.Colorspaces { /// @@ -33,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces {nameof( YCbCr), YCbCr.Empty } }; - public static readonly IEnumerable EmptyData = EmptyDataLookup.Select(x => new [] { x.Key }); + public static readonly IEnumerable EmptyData = EmptyDataLookup.Select(x => new[] { x.Key }); public static readonly TheoryData EqualityData = new TheoryData diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs new file mode 100644 index 0000000000..c00a0a2521 --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; + +namespace SixLabors.ImageSharp.Tests.Helpers +{ + using Xunit; + + public class ImageMathsTests + { + [Fact] + public void FasAbsResultMatchesMath() + { + const int X = -33; + int expected = Math.Abs(X); + + Assert.Equal(expected, ImageMaths.FastAbs(X)); + } + + [Fact] + public void Pow2ResultMatchesMath() + { + const float X = -33; + float expected = MathF.Pow(X, 2); + + Assert.Equal(expected, ImageMaths.Pow2(X)); + } + + [Fact] + public void Pow3ResultMatchesMath() + { + const float X = -33; + float expected = MathF.Pow(X, 3); + + Assert.Equal(expected, ImageMaths.Pow3(X)); + } + } +} diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs index 24363173ae..fd156a7e25 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -5,7 +5,7 @@ using System; using System.Collections.Generic; using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation.RgbColorSapce; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.Tests { From 2b9f565b03549f3c09fa0819875d7ea96fd672aa Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Mar 2018 00:39:17 +1100 Subject: [PATCH 007/185] Begin bulk conversion API --- .../Conversion/ColorSpaceConverter.CieLab.cs | 277 +++++++++++++++++- src/ImageSharp/Common/Helpers/Guard.cs | 22 ++ 2 files changed, 298 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 2720b81fe1..17cdb2ef27 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -24,7 +26,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.NotNull(color, nameof(color)); - // Conversion (perserving white point) + // Conversion (preserving white point) CieLab unadapted = CieLchToCieLabConverter.Convert(color); if (!this.IsChromaticAdaptationPerformed) @@ -36,6 +38,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.Adapt(unadapted); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -49,6 +72,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -62,6 +106,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -75,6 +140,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -94,6 +180,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return converter.Convert(adapted); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -107,6 +214,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -120,6 +248,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -133,6 +282,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -146,6 +316,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -159,6 +350,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -172,6 +384,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -185,6 +418,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } + /// /// Converts a into a /// @@ -197,5 +451,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion var xyzColor = this.ToCieXyz(color); return this.ToCieLab(xyzColor); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLab(sp); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index b0546bf9a9..279c67b3e4 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -246,5 +246,27 @@ namespace SixLabors.ImageSharp throw new ArgumentException($"Span-s must be at least of length {minLength}!", parameterName); } } + + /// + /// Verifies that the given 'source' and 'dest' spans are at least of 'minLength' size. + /// Throwing an if the condition is not met. + /// + /// The source element type + /// The destination element type + /// The source span + /// The source parameter name + /// The destination span + /// The destination parameter name + /// The minimum length + public static void SpansMustBeSizedAtLeast( + Span source, + string sourceParamName, + Span dest, + string destParamName, + int minLength) + { + MustBeSizedAtLeast(source, minLength, sourceParamName); + MustBeSizedAtLeast(dest, minLength, destParamName); + } } } From 54687b88f466ee0cc1c492845906b2052fe09716 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Mar 2018 00:46:05 +1100 Subject: [PATCH 008/185] No point inlining a method containing an exception --- .../ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index 0f62046a64..e35a3fd6ee 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -163,8 +163,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion LinearRgb linearOutput = this.Adapt(linearInput); return this.ToRgb(linearOutput); } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] private void CheckChromaticAdaptation() { const string NoAdapterMessage = "Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."; From 6f07ca49a0bd81435a4ef59b3ebdb677c500e613 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Mar 2018 14:10:03 +1100 Subject: [PATCH 009/185] More bulk conversions. Pause now for new System.Memory --- .../Conversion/ColorSpaceConverter.CieLch.cs | 275 ++++++++++++++++++ .../ColorSpaceConverter.CieLchuv.cs | 275 ++++++++++++++++++ 2 files changed, 550 insertions(+) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index ad0d4e311e..3091658e5d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -31,6 +33,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CieLabToCieLchConverter.Convert(adapted); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -44,6 +67,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -57,6 +101,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -70,6 +135,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -83,6 +169,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(labColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -96,6 +203,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -109,6 +237,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -122,6 +271,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -135,6 +305,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -148,6 +339,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -161,6 +373,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -174,6 +407,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLch(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } + /// /// Converts a into a /// @@ -186,5 +440,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion var xyzColor = this.ToCieXyz(color); return this.ToCieLch(xyzColor); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLch dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLch(sp); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 36e504fb1f..05f1a6f309 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -28,6 +30,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -41,6 +64,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -57,6 +101,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CieLuvToCieLchuvConverter.Convert(adapted); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -70,6 +135,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -83,6 +169,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(labColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -96,6 +203,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -109,6 +237,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -122,6 +271,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -135,6 +305,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -148,6 +339,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -161,6 +373,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -174,6 +407,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLchuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } + /// /// Converts a into a /// @@ -186,5 +440,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref source.DangerousGetPinnableReference(); + ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLchuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLchuv(sp); + } + } } } \ No newline at end of file From 33028a942d1ef0192e28e55ffde99247449d46bf Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 3 Mar 2018 22:28:46 +1100 Subject: [PATCH 010/185] Migrate span and fix up benchmarks project --- .../Conversion/ColorSpaceConverter.Adapt.cs | 1 + .../Conversion/ColorSpaceConverter.CieLab.cs | 55 ++++++++++--------- .../Conversion/ColorSpaceConverter.CieLch.cs | 53 +++++++++--------- .../ColorSpaceConverter.CieLchuv.cs | 53 +++++++++--------- .../ImageSharp.Benchmarks.csproj | 12 +--- 5 files changed, 85 insertions(+), 89 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index e35a3fd6ee..76ddcbcd0e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -163,6 +163,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion LinearRgb linearOutput = this.Adapt(linearInput); return this.ToRgb(linearOutput); } + private void CheckChromaticAdaptation() { const string NoAdapterMessage = "Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 17cdb2ef27..174da5ad12 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -48,8 +49,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieLch sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -82,8 +83,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieLchuv sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -116,8 +117,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieLuv sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -150,8 +151,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieXyy sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -190,8 +191,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieXyz sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -224,8 +225,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Cmyk sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -258,8 +259,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Hsl sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -292,8 +293,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Hsv sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -326,8 +327,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref HunterLab sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -360,8 +361,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Lms sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -394,8 +395,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref LinearRgb sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -428,8 +429,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Rgb sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -462,12 +463,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref YCbCr sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLab destRef = ref destination.DangerousGetPinnableReference(); + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLab destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { - ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); ref CieLab dp = ref Unsafe.Add(ref destRef, i); dp = this.ToCieLab(sp); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 3091658e5d..8ce8674a64 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -43,8 +44,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieLab sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -77,8 +78,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieLchuv sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -111,8 +112,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieLuv sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -145,8 +146,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieXyy sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -179,8 +180,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieXyz sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -213,8 +214,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Cmyk sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -247,8 +248,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Hsl sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -281,8 +282,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Hsv sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -315,8 +316,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref HunterLab sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -349,8 +350,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref LinearRgb sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -383,8 +384,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Lms sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -417,8 +418,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Rgb sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -451,8 +452,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref YCbCr sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLch destRef = ref destination.DangerousGetPinnableReference(); + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLch destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 05f1a6f309..e4feddc7e2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -40,8 +41,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieLab sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -74,8 +75,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieLch sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -111,8 +112,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieLuv sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -145,8 +146,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieXyy sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -179,8 +180,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref CieXyz sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -213,8 +214,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Cmyk sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -247,8 +248,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Hsl sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -281,8 +282,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Hsv sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -315,8 +316,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref HunterLab sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -349,8 +350,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref LinearRgb sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -383,8 +384,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Lms sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -417,8 +418,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref Rgb sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { @@ -451,8 +452,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - ref YCbCr sourceRef = ref source.DangerousGetPinnableReference(); - ref CieLchuv destRef = ref destination.DangerousGetPinnableReference(); + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLchuv destRef = ref MemoryMarshal.GetReference(destination); for (int i = 0; i < count; i++) { diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 62fd11e8e4..74b9601c65 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -15,20 +15,12 @@ - - - - - - - - - + + - From b5ec7afc21ffa5824b09cbc0e3334f2c812d2a58 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 3 Mar 2018 23:51:48 +1100 Subject: [PATCH 011/185] Add bulk conversion to CieLuv --- .../Conversion/ColorSpaceConverter.CieLuv.cs | 276 ++++++++++++++++++ 1 file changed, 276 insertions(+) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index 498f0cc9d0..f4b52a49ab 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; @@ -26,6 +29,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -39,6 +63,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -60,6 +105,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.Adapt(unadapted); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -73,6 +139,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -92,6 +179,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return converter.Convert(adapted); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -105,6 +213,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -118,6 +247,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -131,6 +281,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -144,6 +315,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -157,6 +349,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -170,6 +383,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -183,6 +417,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieLuv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } + /// /// Converts a into a /// @@ -195,5 +450,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion var xyzColor = this.ToCieXyz(color); return this.ToCieLuv(xyzColor); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref CieLuv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref CieLuv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieLuv(sp); + } + } } } \ No newline at end of file From 96d27c46eae034f07babf637c45d283f783435dd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 12 Jul 2018 19:44:18 +1000 Subject: [PATCH 012/185] Simplify structs, 5% perf increase. --- src/ImageSharp/ColorSpaces/CieLab.cs | 126 ++--- src/ImageSharp/ColorSpaces/CieLch.cs | 122 ++--- src/ImageSharp/ColorSpaces/CieLchuv.cs | 127 ++--- src/ImageSharp/ColorSpaces/CieLuv.cs | 129 ++--- .../CieXyChromaticityCoordinates.cs | 92 +--- src/ImageSharp/ColorSpaces/CieXyy.cs | 108 ++-- src/ImageSharp/ColorSpaces/CieXyz.cs | 108 ++-- src/ImageSharp/ColorSpaces/Cmyk.cs | 126 ++--- .../Implementation/CieXyzAndLmsConverter.cs | 4 +- .../CieXyzToLinearRgbConverter.cs | 2 +- .../Implementation/CmykAndRgbConverter.cs | 2 +- .../LinearRgbAndCieXyzConverterBase.cs | 26 +- .../LinearRgbToCieXyzConverter.cs | 2 +- .../Implementation/LinearRgbToRgbConverter.cs | 2 +- .../Implementation/RgbToLinearRgbConverter.cs | 2 +- .../Implementation/YCbCrAndRgbConverter.cs | 2 +- .../Conversion/VonKriesChromaticAdaptation.cs | 4 +- src/ImageSharp/ColorSpaces/Hsl.cs | 104 ++-- src/ImageSharp/ColorSpaces/Hsv.cs | 107 ++-- src/ImageSharp/ColorSpaces/HunterLab.cs | 120 ++--- src/ImageSharp/ColorSpaces/IColorVector.cs | 18 - .../ColorSpaces/IRgbWorkingSpace.cs | 31 -- src/ImageSharp/ColorSpaces/LinearRgb.cs | 125 ++--- src/ImageSharp/ColorSpaces/Lms.cs | 119 ++--- src/ImageSharp/ColorSpaces/Rgb.cs | 126 ++--- src/ImageSharp/ColorSpaces/YCbCr.cs | 108 ++-- .../Colorspaces/ColorSpaceEqualityTests.cs | 498 +++++++++--------- 27 files changed, 861 insertions(+), 1479 deletions(-) delete mode 100644 src/ImageSharp/ColorSpaces/IColorVector.cs delete mode 100644 src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 82975d9330..3b2815dd72 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -12,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents a CIE L*a*b* 1976 color. /// /// - internal readonly struct CieLab : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieLab : IEquatable { /// /// D50 standard illuminant. @@ -21,9 +20,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public readonly float L; + + /// + /// Gets the a color component. + /// A value ranging from -100 to 100. Negative is green, positive magenta. + /// + public readonly float A; + + /// + /// Gets the b color component. + /// A value ranging from -100 to 100. Negative is blue, positive is yellow + /// + public readonly float B; + + /// + /// Gets the reference white point of this color /// - private readonly Vector3 backingVector; + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -34,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Uses as white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLab(float l, float a, float b) - : this(new Vector3(l, a, b), DefaultWhitePoint) + : this(l, a, b, DefaultWhitePoint) { } @@ -47,8 +64,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLab(float l, float a, float b, CieXyz whitePoint) - : this(new Vector3(l, a, b), whitePoint) { + this.L = l; + this.A = a; + this.B = b; + this.WhitePoint = whitePoint; } /// @@ -71,88 +91,41 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieLab(Vector3 vector, CieXyz whitePoint) : this() { - this.backingVector = vector; + this.L = vector.X; + this.A = vector.Y; + this.B = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the a color component. - /// A value ranging from -100 to 100. Negative is green, positive magenta. - /// - public float A - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the b color component. - /// A value ranging from -100 to 100. Negative is blue, positive is yellow - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(CieLab left, CieLab right) - { - return left.Equals(right); - } + public static bool operator ==(CieLab left, CieLab right) => left.Equals(right); /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(CieLab left, CieLab right) - { - return !left.Equals(right); - } + public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right); /// public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.A.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -164,29 +137,16 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieLab other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieLab other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLab other) { - return this.backingVector.Equals(other.backingVector) + return this.L.Equals(other.L) + && this.A.Equals(other.A) + && this.B.Equals(other.B) && this.WhitePoint.Equals(other.WhitePoint); } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieLab other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; - } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index 67a9956bdc..eea9e24a31 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -12,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents the CIE L*C*h°, cylindrical form of the CIE L*a*b* 1976 color. /// /// - internal readonly struct CieLch : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieLch : IEquatable { /// /// D50 standard illuminant. @@ -21,9 +20,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.D50; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public readonly float L; + + /// + /// Gets the a chroma component. + /// A value ranging from 0 to 100. /// - private readonly Vector3 backingVector; + public readonly float C; + + /// + /// Gets the h° hue component in degrees. + /// A value ranging from 0 to 360. + /// + public readonly float H; + + /// + /// Gets the reference white point of this color + /// + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -34,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Uses as white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(float l, float c, float h) - : this(new Vector3(l, c, h), DefaultWhitePoint) + : this(l, c, h, DefaultWhitePoint) { } @@ -47,8 +64,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(float l, float c, float h, CieXyz whitePoint) - : this(new Vector3(l, c, h), whitePoint) { + this.L = l; + this.C = c; + this.H = h; + this.WhitePoint = whitePoint; } /// @@ -69,59 +89,18 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch(Vector3 vector, CieXyz whitePoint) - : this() { - this.backingVector = vector; + this.L = vector.X; + this.C = vector.Y; + this.H = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the a chroma component. - /// A value ranging from 0 to 100. - /// - public float C - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the h° hue component in degrees. - /// A value ranging from 0 to 360. - /// - public float H - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// @@ -134,25 +113,21 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(CieLch left, CieLch right) - { - return !left.Equals(right); - } + public static bool operator !=(CieLch left, CieLch right) => !left.Equals(right); /// public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.C.GetHashCode()); + hash = HashHelpers.Combine(hash, this.H.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -165,31 +140,18 @@ namespace SixLabors.ImageSharp.ColorSpaces /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override bool Equals(object obj) - { - return obj is CieLch other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieLch other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLch other) { - return this.backingVector.Equals(other.backingVector) + return this.L.Equals(other.L) + && this.C.Equals(other.C) + && this.H.Equals(other.H) && this.WhitePoint.Equals(other.WhitePoint); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieLch other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; - } - /// /// Computes the saturation of the color (chroma normalized by lightness) /// diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index 0b4c7a9036..6538ccbbcf 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -12,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color. /// /// - internal readonly struct CieLchuv : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieLchuv : IEquatable { /// /// D50 standard illuminant. @@ -21,9 +20,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public readonly float L; + + /// + /// Gets the a chroma component. + /// A value ranging from 0 to 100. + /// + public readonly float C; + + /// + /// Gets the h° hue component in degrees. + /// A value ranging from 0 to 360. + /// + public readonly float H; + + /// + /// Gets the reference white point of this color /// - private readonly Vector3 backingVector; + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -34,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Uses as white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLchuv(float l, float c, float h) - : this(new Vector3(l, c, h), DefaultWhitePoint) + : this(l, c, h, DefaultWhitePoint) { } @@ -47,8 +64,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLchuv(float l, float c, float h, CieXyz whitePoint) - : this(new Vector3(l, c, h), whitePoint) { + this.L = l; + this.C = c; + this.H = h; + this.WhitePoint = whitePoint; } /// @@ -71,87 +91,39 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieLchuv(Vector3 vector, CieXyz whitePoint) : this() { - this.backingVector = vector; + this.L = vector.X; + this.C = vector.Y; + this.H = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the a chroma component. - /// A value ranging from 0 to 100. - /// - public float C - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the h° hue component in degrees. - /// A value ranging from 0 to 360. - /// - public float H - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// - public static bool operator ==(CieLchuv left, CieLchuv right) - { - return left.Equals(right); - } + public static bool operator ==(CieLchuv left, CieLchuv right) => left.Equals(right); /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// - public static bool operator !=(CieLchuv left, CieLchuv right) - { - return !left.Equals(right); - } + public static bool operator !=(CieLchuv left, CieLchuv right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.C.GetHashCode()); + hash = HashHelpers.Combine(hash, this.H.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -163,31 +135,18 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieLchuv other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLchuv other) { - return this.backingVector.Equals(other.backingVector) + return this.L.Equals(other.L) + && this.C.Equals(other.C) + && this.H.Equals(other.H) && this.WhitePoint.Equals(other.WhitePoint); } - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieLchuv other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; - } - /// /// Computes the saturation of the color (chroma normalized by lightness) /// diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index dbc3b6dee5..970362eaec 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -14,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// attempted perceptual uniformity /// /// - internal readonly struct CieLuv : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieLuv : IEquatable { /// /// D65 standard illuminant. @@ -23,9 +22,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension + /// A value usually ranging between 0 and 100. + /// + public readonly float L; + + /// + /// Gets the blue-yellow chromaticity coordinate of the given whitepoint. + /// A value usually ranging between -100 and 100. + /// + public readonly float U; + + /// + /// Gets the red-green chromaticity coordinate of the given whitepoint. + /// A value usually ranging between -100 and 100. + /// + public readonly float V; + + /// + /// Gets the reference white point of this color /// - private readonly Vector3 backingVector; + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -36,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Uses as white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv(float l, float u, float v) - : this(new Vector3(l, u, v), DefaultWhitePoint) + : this(l, u, v, DefaultWhitePoint) { } @@ -49,8 +66,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv(float l, float u, float v, CieXyz whitePoint) - : this(new Vector3(l, u, v), whitePoint) { + this.L = l; + this.U = u; + this.V = v; + this.WhitePoint = whitePoint; } /// @@ -71,90 +91,42 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv(Vector3 vector, CieXyz whitePoint) - : this() { - this.backingVector = vector; + this.L = vector.X; + this.U = vector.Y; + this.V = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension - /// A value usually ranging between 0 and 100. - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the blue-yellow chromaticity coordinate of the given whitepoint. - /// A value usually ranging between -100 and 100. - /// - public float U - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the red-green chromaticity coordinate of the given whitepoint. - /// A value usually ranging between -100 and 100. - /// - public float V - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(CieLuv left, CieLuv right) - { - return left.Equals(right); - } + public static bool operator ==(CieLuv left, CieLuv right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(CieLuv left, CieLuv right) - { - return !left.Equals(right); - } + public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right); /// public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.U.GetHashCode()); + hash = HashHelpers.Combine(hash, this.V.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -166,29 +138,16 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieLuv other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieLuv other) { - return this.backingVector.Equals(other.backingVector) - && this.WhitePoint.Equals(other.WhitePoint); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieLuv other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.L.Equals(other.L) + && this.U.Equals(other.U) + && this.V.Equals(other.V) + && this.WhitePoint.Equals(other.WhitePoint); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs index 4f4f951472..de6725f760 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs @@ -2,8 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; -using System.Numerics; using System.Runtime.CompilerServices; // ReSharper disable CompareOfFloatsByEqualityOperator @@ -12,45 +10,15 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents the coordinates of CIEXY chromaticity space /// - internal readonly struct CieXyChromaticityCoordinates : IEquatable, IAlmostEquatable + internal readonly struct CieXyChromaticityCoordinates : IEquatable { - /// - /// The backing vector for SIMD support. - /// - private readonly Vector2 backingVector; - - /// - /// Initializes a new instance of the struct. - /// - /// Chromaticity coordinate x (usually from 0 to 1) - /// Chromaticity coordinate y (usually from 0 to 1) - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public CieXyChromaticityCoordinates(float x, float y) - : this(new Vector2(x, y)) - { - } - - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the XY Chromaticity coordinates - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public CieXyChromaticityCoordinates(Vector2 vector) - { - this.backingVector = vector; - } - /// /// Gets the chromaticity X-coordinate. /// /// /// Ranges usually from 0 to 1. /// - public float X - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } + public readonly float X; /// /// Gets the chromaticity Y-coordinate @@ -58,21 +26,25 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Ranges usually from 0 to 1. /// - public float Y + public readonly float Y; + + /// + /// Initializes a new instance of the struct. + /// + /// Chromaticity coordinate x (usually from 0 to 1) + /// Chromaticity coordinate y (usually from 0 to 1) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public CieXyChromaticityCoordinates(float x, float y) { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; + this.X = x; + this.Y = y; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// @@ -85,12 +57,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// @@ -102,10 +70,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public override int GetHashCode() - { - return this.backingVector.GetHashCode(); - } + public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode()); /// public override string ToString() @@ -116,27 +81,10 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieXyChromaticityCoordinates other && this.Equals(other); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(CieXyChromaticityCoordinates other) - { - // The memberwise comparison here is a workaround for https://github.com/dotnet/coreclr/issues/16443 - return this.X == other.X && this.Y == other.Y; - } + public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieXyChromaticityCoordinates other, float precision) - { - var result = Vector2.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision; - } + public bool Equals(CieXyChromaticityCoordinates other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index ac1a4532c5..976454a31b 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -12,12 +11,25 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents an CIE xyY 1931 color /// /// - internal readonly struct CieXyy : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieXyy : IEquatable { /// - /// The backing vector for SIMD support. + /// Gets the X chrominance component. + /// A value usually ranging between 0 and 1. + /// + public readonly float X; + + /// + /// Gets the Y chrominance component. + /// A value usually ranging between 0 and 1. + /// + public readonly float Y; + + /// + /// Gets the Y luminance component. + /// A value usually ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float Yl; /// /// Initializes a new instance of the struct. @@ -27,8 +39,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The y luminance component. [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyy(float x, float y, float yl) - : this(new Vector3(x, y, yl)) { + // Not clamping as documentation about this space seems to indicate "usual" ranges + this.X = x; + this.Y = y; + this.Yl = yl; } /// @@ -40,83 +55,39 @@ namespace SixLabors.ImageSharp.ColorSpaces : this() { // Not clamping as documentation about this space seems to indicate "usual" ranges - this.backingVector = vector; - } - - /// - /// Gets the X chrominance component. - /// A value usually ranging between 0 and 1. - /// - public float X - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the Y chrominance component. - /// A value usually ranging between 0 and 1. - /// - public float Y - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the Y luminance component. - /// A value usually ranging between 0 and 1. - /// - public float Yl - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; + this.X = vector.X; + this.Y = vector.Y; + this.Yl = vector.Z; } - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(CieXyy left, CieXyy right) - { - return left.Equals(right); - } + public static bool operator ==(CieXyy left, CieXyy right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(CieXyy left, CieXyy right) - { - return !left.Equals(right); - } + public static bool operator !=(CieXyy left, CieXyy right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.X.GetHashCode(); + hash = HashHelpers.Combine(hash, this.Y.GetHashCode()); + return HashHelpers.Combine(hash, this.Yl.GetHashCode()); } /// @@ -137,18 +108,9 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieXyy other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieXyy other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.X.Equals(other.X) + && this.Y.Equals(other.Y) + && this.Yl.Equals(other.Yl); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index fa4261b46d..d23be97449 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -12,12 +12,25 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents an CIE XYZ 1931 color /// /// - internal readonly struct CieXyz : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct CieXyz : IEquatable { /// - /// The backing vector for SIMD support. + /// Gets the X component. A mix (a linear combination) of cone response curves chosen to be nonnegative. + /// A value usually ranging between 0 and 1. + /// + public readonly float X; + + /// + /// Gets the Y luminance component. + /// A value usually ranging between 0 and 1. + /// + public readonly float Y; + + /// + /// Gets the Z component. Quasi-equal to blue stimulation, or the S cone response + /// A value usually ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float Z; /// /// Initializes a new instance of the struct. @@ -29,6 +42,10 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieXyz(float x, float y, float z) : this(new Vector3(x, y, z)) { + // Not clamping as documentation about this space seems to indicate "usual" ranges + this.X = x; + this.Y = y; + this.Z = z; } /// @@ -39,51 +56,16 @@ namespace SixLabors.ImageSharp.ColorSpaces : this() { // Not clamping as documentation about this space seems to indicate "usual" ranges - this.backingVector = vector; - } - - /// - /// Gets the X component. A mix (a linear combination) of cone response curves chosen to be nonnegative. - /// A value usually ranging between 0 and 1. - /// - public float X - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the Y luminance component. - /// A value usually ranging between 0 and 1. - /// - public float Y - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the Z component. Quasi-equal to blue stimulation, or the S cone response - /// A value usually ranging between 0 and 1. - /// - public float Z - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; + this.X = vector.X; + this.Y = vector.Y; + this.Z = vector.Z; } - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// @@ -96,12 +78,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// @@ -111,11 +89,19 @@ namespace SixLabors.ImageSharp.ColorSpaces return !left.Equals(right); } - /// + /// + /// Returns a new representing this instance. + /// + /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new Vector3(this.X, this.Y, this.Z); + + /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.X.GetHashCode(); + hash = HashHelpers.Combine(hash, this.Y.GetHashCode()); + return HashHelpers.Combine(hash, this.Z.GetHashCode()); } /// @@ -127,27 +113,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is CieXyz other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(CieXyz other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(CieXyz other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.X.Equals(other.X) + && this.Y.Equals(other.Y) + && this.Z.Equals(other.Z); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index 2702d4ba33..711e9867f7 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -11,12 +10,31 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents an CMYK (cyan, magenta, yellow, keyline) color. /// - internal readonly struct Cmyk : IEquatable, IAlmostEquatable + internal readonly struct Cmyk : IEquatable { /// - /// The backing vector for SIMD support. + /// Gets the cyan color component. + /// A value ranging between 0 and 1. + /// + public readonly float C; + + /// + /// Gets the magenta color component. + /// A value ranging between 0 and 1. /// - private readonly Vector4 backingVector; + public readonly float M; + + /// + /// Gets the yellow color component. + /// A value ranging between 0 and 1. + /// + public readonly float Y; + + /// + /// Gets the keyline black color component. + /// A value ranging between 0 and 1. + /// + public readonly float K; /// /// Initializes a new instance of the struct. @@ -37,92 +55,44 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The vector representing the c, m, y, k components. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cmyk(Vector4 vector) - : this() - { - this.backingVector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); - } - - /// - /// Gets the cyan color component. - /// A value ranging between 0 and 1. - /// - public float C { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the magenta color component. - /// A value ranging between 0 and 1. - /// - public float M - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the yellow color component. - /// A value ranging between 0 and 1. - /// - public float Y - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - /// Gets the keyline black color component. - /// A value ranging between 0 and 1. - /// - public float K - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.W; + vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + this.C = vector.X; + this.Y = vector.Y; + this.M = vector.Z; + this.K = vector.W; } /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Cmyk left, Cmyk right) - { - return left.Equals(right); - } + public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right); /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Cmyk left, Cmyk right) - { - return !left.Equals(right); - } + public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.C.GetHashCode(); + hash = HashHelpers.Combine(hash, this.M.GetHashCode()); + hash = HashHelpers.Combine(hash, this.Y.GetHashCode()); + return HashHelpers.Combine(hash, this.K.GetHashCode()); } /// @@ -134,28 +104,16 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Cmyk other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Cmyk other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Cmyk other, float precision) - { - var result = Vector4.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision - && result.W <= precision; + return this.C.Equals(other.C) + && this.M.Equals(other.M) + && this.Y.Equals(other.Y) + && this.K.Equals(other.K); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs index 513a928c7a..e3a031e82c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms Convert(in CieXyz input) { - var vector = Vector3.Transform(input.Vector, this.transformationMatrix); + var vector = Vector3.Transform(input.ToVector3(), this.transformationMatrix); return new Lms(vector); } @@ -72,7 +72,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(in Lms input) { - var vector = Vector3.Transform(input.Vector, this.inverseTransformationMatrix); + var vector = Vector3.Transform(input.ToVector3(), this.inverseTransformationMatrix); return new CieXyz(vector); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs index 0ceb05fd9d..a2786654fe 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public LinearRgb Convert(in CieXyz input) { Matrix4x4.Invert(this.conversionMatrix, out Matrix4x4 inverted); - var vector = Vector3.Transform(input.Vector, inverted); + var vector = Vector3.Transform(input.ToVector3(), inverted); return new LinearRgb(vector, this.TargetWorkingSpace); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs index 649e984009..26d15beb3c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public Cmyk Convert(in Rgb input) { // To CMYK - Vector3 cmy = Vector3.One - input.Vector; + Vector3 cmy = Vector3.One - input.ToVector3(); // To CMYK var k = new Vector3(MathF.Min(cmy.X, MathF.Min(cmy.Y, cmy.Z))); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs index 492d4a58ff..a9d8e83983 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs @@ -42,23 +42,35 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation var xyzMatrix = new Matrix4x4 { - M11 = mXr, M21 = mXg, M31 = mXb, - M12 = Yr, M22 = Yg, M32 = Yb, - M13 = mZr, M23 = mZg, M33 = mZb, + M11 = mXr, + M21 = mXg, + M31 = mXb, + M12 = Yr, + M22 = Yg, + M32 = Yb, + M13 = mZr, + M23 = mZg, + M33 = mZb, M44 = 1F }; Matrix4x4.Invert(xyzMatrix, out Matrix4x4 inverseXyzMatrix); - var vector = Vector3.Transform(workingSpace.WhitePoint.Vector, inverseXyzMatrix); + var vector = Vector3.Transform(workingSpace.WhitePoint.ToVector3(), inverseXyzMatrix); // Use transposed Rows/Columns // TODO: Is there a built in method for this multiplication? return new Matrix4x4 { - M11 = vector.X * mXr, M21 = vector.Y * mXg, M31 = vector.Z * mXb, - M12 = vector.X * Yr, M22 = vector.Y * Yg, M32 = vector.Z * Yb, - M13 = vector.X * mZr, M23 = vector.Y * mZg, M33 = vector.Z * mZb, + M11 = vector.X * mXr, + M21 = vector.Y * mXg, + M31 = vector.Z * mXb, + M12 = vector.X * Yr, + M22 = vector.Y * Yg, + M32 = vector.Z * Yb, + M13 = vector.X * mZr, + M23 = vector.Y * mZg, + M33 = vector.Z * mZb, M44 = 1F }; } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs index 113ec0e7e1..80849021f0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); - var vector = Vector3.Transform(input.Vector, this.conversionMatrix); + var vector = Vector3.Transform(input.ToVector3(), this.conversionMatrix); return new CieXyz(vector); } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs index 6c43b00a35..a985f8ed54 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public Rgb Convert(in LinearRgb input) { - Vector3 vector = input.Vector; + Vector3 vector = input.ToVector3(); vector.X = input.WorkingSpace.Companding.Compress(vector.X); vector.Y = input.WorkingSpace.Companding.Compress(vector.Y); vector.Z = input.WorkingSpace.Companding.Compress(vector.Z); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs index 2229c807e9..c8d04c54ac 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public LinearRgb Convert(in Rgb input) { - Vector3 vector = input.Vector; + Vector3 vector = input.ToVector3(); vector.X = input.WorkingSpace.Companding.Expand(vector.X); vector.Y = input.WorkingSpace.Companding.Expand(vector.Y); vector.Z = input.WorkingSpace.Companding.Expand(vector.Z); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs index 99e2ca1bd5..5d2cd85ba2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr Convert(in Rgb input) { - Vector3 rgb = input.Vector * MaxBytes; + Vector3 rgb = input.ToVector3() * MaxBytes; float r = rgb.X; float g = rgb.Y; float b = rgb.Z; diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index 01aeb25569..f3d74b6f80 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -58,8 +58,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint); Lms targetWhitePointLms = this.converter.Convert(targetWhitePoint); - Vector3 vector = targetWhitePointLms.Vector / sourceWhitePointLms.Vector; - var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.Vector)); + Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3(); + var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3())); return this.converter.Convert(targetColorLms); } diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index 8ed4067539..14dfc5d1ac 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -11,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents a Hsl (hue, saturation, lightness) color. /// - internal readonly struct Hsl : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct Hsl : IEquatable { /// /// Max range used for clamping. @@ -19,9 +18,22 @@ namespace SixLabors.ImageSharp.ColorSpaces private static readonly Vector3 VectorMax = new Vector3(360, 1, 1); /// - /// The backing vector for SIMD support. + /// Gets the hue component. + /// A value ranging between 0 and 360. + /// + public readonly float H; + + /// + /// Gets the saturation component. + /// A value ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float S; + + /// + /// Gets the lightness component. + /// A value ranging between 0 and 1. + /// + public readonly float L; /// /// Initializes a new instance of the struct. @@ -42,83 +54,43 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hsl(Vector3 vector) { - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); - } - - /// - /// Gets the hue component. - /// A value ranging between 0 and 360. - /// - public float H - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the saturation component. - /// A value ranging between 0 and 1. - /// - public float S - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; + vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + this.H = vector.X; + this.S = vector.Y; + this.L = vector.Z; } - /// - /// Gets the lightness component. - /// A value ranging between 0 and 1. - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// /// /// The on the left side of the operand. /// - /// - /// The on the right side of the operand. - /// + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Hsl left, Hsl right) - { - return left.Equals(right); - } + public static bool operator ==(Hsl left, Hsl right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Hsl left, Hsl right) - { - return !left.Equals(right); - } + public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.H.GetHashCode(); + hash = HashHelpers.Combine(hash, this.S.GetHashCode()); + return HashHelpers.Combine(hash, this.L.GetHashCode()); } /// @@ -130,27 +102,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Hsl other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Hsl other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Hsl other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Hsl other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.H.Equals(other.H) + && this.S.Equals(other.S) + && this.L.Equals(other.L); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index 78a49097ed..1035f94bf2 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness). /// - internal readonly struct Hsv : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct Hsv : IEquatable { /// /// Max range used for clamping. @@ -21,9 +21,22 @@ namespace SixLabors.ImageSharp.ColorSpaces private static readonly Vector3 VectorMax = new Vector3(360, 1, 1); /// - /// The backing vector for SIMD support. + /// Gets the hue component. + /// A value ranging between 0 and 360. + /// + public readonly float H; + + /// + /// Gets the saturation component. + /// A value ranging between 0 and 1. + /// + public readonly float S; + + /// + /// Gets the value (brightness) component. + /// A value ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float V; /// /// Initializes a new instance of the struct. @@ -44,42 +57,12 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hsv(Vector3 vector) { - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + this.H = vector.X; + this.S = vector.Y; + this.V = vector.Z; } - /// - /// Gets the hue component. - /// A value ranging between 0 and 360. - /// - public float H - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the saturation component. - /// A value ranging between 0 and 1. - /// - public float S - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the value (brightness) component. - /// A value ranging between 0 and 1. - /// - public float V - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Allows the implicit conversion of an instance of to a /// . @@ -133,44 +116,32 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Hsv left, Hsv right) - { - return left.Equals(right); - } + public static bool operator ==(Hsv left, Hsv right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Hsv left, Hsv right) - { - return !left.Equals(right); - } + public static bool operator !=(Hsv left, Hsv right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.H.GetHashCode(); + hash = HashHelpers.Combine(hash, this.S.GetHashCode()); + return HashHelpers.Combine(hash, this.V.GetHashCode()); } /// @@ -182,27 +153,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Hsv other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Hsv other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Hsv other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Hsv other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.H.Equals(other.H) + && this.S.Equals(other.S) + && this.V.Equals(other.V); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index 44f31bc295..2f8da5a9a3 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents an Hunter LAB color. /// /// - internal readonly struct HunterLab : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct HunterLab : IEquatable { /// /// D50 standard illuminant. @@ -21,9 +21,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly CieXyz DefaultWhitePoint = Illuminants.C; /// - /// The backing vector for SIMD support. + /// Gets the lightness dimension. + /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// + public readonly float L; + + /// + /// Gets the a color component. + /// A value ranging from -100 to 100. Negative is green, positive magenta. /// - private readonly Vector3 backingVector; + public readonly float A; + + /// + /// Gets the b color component. + /// A value ranging from -100 to 100. Negative is blue, positive is yellow + /// + public readonly float B; + + /// + /// Gets the reference white point of this color + /// + public readonly CieXyz WhitePoint; /// /// Initializes a new instance of the struct. @@ -69,90 +87,43 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(MethodImplOptions.AggressiveInlining)] public HunterLab(Vector3 vector, CieXyz whitePoint) - : this() { - this.backingVector = vector; + // TODO: Clamp? + this.L = vector.X; + this.A = vector.Y; + this.B = vector.Z; this.WhitePoint = whitePoint; } - /// - /// Gets the reference white point of this color - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the a color component. - /// A value ranging from -100 to 100. Negative is green, positive magenta. - /// - public float A - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the b color component. - /// A value ranging from -100 to 100. Negative is blue, positive is yellow - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// - public static bool operator ==(HunterLab left, HunterLab right) - { - return left.Equals(right); - } + public static bool operator ==(HunterLab left, HunterLab right) => left.Equals(right); /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(HunterLab left, HunterLab right) - { - return !left.Equals(right); - } + public static bool operator !=(HunterLab left, HunterLab right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return HashHelpers.Combine(this.WhitePoint.GetHashCode(), this.backingVector.GetHashCode()); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.A.GetHashCode()); + hash = HashHelpers.Combine(hash, this.B.GetHashCode()); + return HashHelpers.Combine(hash, this.WhitePoint.GetHashCode()); } /// @@ -164,29 +135,16 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is HunterLab other && this.Equals(other); - } + public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(HunterLab other) { - return this.backingVector.Equals(other.backingVector) + return this.L.Equals(other.L) + && this.A.Equals(other.A) + && this.B.Equals(other.B) && this.WhitePoint.Equals(other.WhitePoint); } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(HunterLab other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return this.WhitePoint.Equals(other.WhitePoint) - && result.X <= precision - && result.Y <= precision - && result.Z <= precision; - } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/IColorVector.cs b/src/ImageSharp/ColorSpaces/IColorVector.cs deleted file mode 100644 index 85c040b868..0000000000 --- a/src/ImageSharp/ColorSpaces/IColorVector.cs +++ /dev/null @@ -1,18 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; - -namespace SixLabors.ImageSharp.ColorSpaces -{ - /// - /// Color represented as a vector in its color space - /// - internal interface IColorVector - { - /// - /// Gets the vector representation of the color - /// - Vector3 Vector { get; } - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs deleted file mode 100644 index 00a714c6f8..0000000000 --- a/src/ImageSharp/ColorSpaces/IRgbWorkingSpace.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - -namespace SixLabors.ImageSharp.ColorSpaces -{ - /// - /// Encasulates the RGB working color space - /// - internal interface IRgbWorkingSpace : IEquatable - { - /// - /// Gets the reference white of the color space. - /// - CieXyz WhitePoint { get; } - - /// - /// Gets the chromaticity coordinates of the primaries. - /// - RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; } - - /// - /// Gets the companding function associated with the RGB color system. Used for conversion to XYZ and backwards. - /// - /// - /// - ICompanding Companding { get; } - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index d0aeba75ac..e9e06c0bbb 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents an linear Rgb color with specified working space /// - internal readonly struct LinearRgb : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct LinearRgb : IEquatable { /// /// The default LinearRgb working space. @@ -19,9 +19,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; /// - /// The backing vector for SIMD support. + /// Gets the red component. + /// A value usually ranging between 0 and 1. + /// + public readonly float R; + + /// + /// Gets the green component. + /// A value usually ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float G; + + /// + /// Gets the blue component. + /// A value usually ranging between 0 and 1. + /// + public readonly float B; + + /// + /// Gets the LinearRgb color space + /// + public readonly RgbWorkingSpace WorkingSpace; /// /// Initializes a new instance of the struct. @@ -65,92 +83,51 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The LinearRgb working space. [MethodImpl(MethodImplOptions.AggressiveInlining)] public LinearRgb(Vector3 vector, RgbWorkingSpace workingSpace) - : this() { // Clamp to 0-1 range. - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + this.R = vector.X; + this.G = vector.Y; + this.B = vector.Z; this.WorkingSpace = workingSpace; } - /// - /// Gets the red component. - /// A value usually ranging between 0 and 1. - /// - public float R - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the green component. - /// A value usually ranging between 0 and 1. - /// - public float G - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the blue component. - /// A value usually ranging between 0 and 1. - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - /// Gets the LinearRgb color space - /// - public RgbWorkingSpace WorkingSpace { get; } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(LinearRgb left, LinearRgb right) - { - return left.Equals(right); - } + public static bool operator ==(LinearRgb left, LinearRgb right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(LinearRgb left, LinearRgb right) - { - return !left.Equals(right); - } + public static bool operator !=(LinearRgb left, LinearRgb right) => !left.Equals(right); + + /// + /// Returns a new representing this instance. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new Vector3(this.R, this.G, this.B); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.R.GetHashCode(); + hash = HashHelpers.Combine(hash, this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } /// @@ -162,27 +139,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is LinearRgb other && this.Equals(other); - } + public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(LinearRgb other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(LinearRgb other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 9b0331e0bc..5c471649d3 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -13,12 +12,25 @@ namespace SixLabors.ImageSharp.ColorSpaces /// named after their responsivity (sensitivity) at long, medium and short wavelengths. /// /// - internal readonly struct Lms : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct Lms : IEquatable { /// - /// The backing vector for SIMD support. + /// Gets the L long component. + /// A value usually ranging between -1 and 1. + /// + public readonly float L; + + /// + /// Gets the M medium component. + /// A value usually ranging between -1 and 1. /// - private readonly Vector3 backingVector; + public readonly float M; + + /// + /// Gets the S short component. + /// A value usually ranging between -1 and 1. + /// + public readonly float S; /// /// Initializes a new instance of the struct. @@ -28,8 +40,10 @@ namespace SixLabors.ImageSharp.ColorSpaces /// S represents the responsivity at short wavelengths. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms(float l, float m, float s) - : this(new Vector3(l, m, s)) { + this.L = l; + this.M = m; + this.S = s; } /// @@ -38,85 +52,48 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The vector representing the l, m, s components. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms(Vector3 vector) - : this() { // Not clamping as documentation about this space seems to indicate "usual" ranges - this.backingVector = vector; - } - - /// - /// Gets the L long component. - /// A value usually ranging between -1 and 1. - /// - public float L - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the M medium component. - /// A value usually ranging between -1 and 1. - /// - public float M - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; + this.L = vector.X; + this.M = vector.Y; + this.S = vector.Z; } - /// - /// Gets the S short component. - /// A value usually ranging between -1 and 1. - /// - public float S - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Lms left, Lms right) - { - return left.Equals(right); - } + public static bool operator ==(Lms left, Lms right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Lms left, Lms right) - { - return !left.Equals(right); - } + public static bool operator !=(Lms left, Lms right) => !left.Equals(right); + + /// + /// Returns a new representing this instance. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new Vector3(this.L, this.M, this.S); /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.L.GetHashCode(); + hash = HashHelpers.Combine(hash, this.M.GetHashCode()); + return HashHelpers.Combine(hash, this.S.GetHashCode()); } /// @@ -128,27 +105,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Lms other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Lms other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Lms other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Lms other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.L.Equals(other.L) + && this.M.Equals(other.M) + && this.S.Equals(other.S); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 74b0c5bc85..7c8437d6e2 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -10,9 +10,9 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.ColorSpaces { /// - /// Represents an RGB color with specified working space + /// Represents an RGB color with specified working space. /// - internal readonly struct Rgb : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct Rgb : IEquatable { /// /// The default rgb working space @@ -20,9 +20,27 @@ namespace SixLabors.ImageSharp.ColorSpaces public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; /// - /// The backing vector for SIMD support. + /// Gets the red component. + /// A value usually ranging between 0 and 1. /// - private readonly Vector3 backingVector; + public readonly float R; + + /// + /// Gets the green component. + /// A value usually ranging between 0 and 1. + /// + public readonly float G; + + /// + /// Gets the blue component. + /// A value usually ranging between 0 and 1. + /// + public readonly float B; + + /// + /// Gets the Rgb color space + /// + public readonly RgbWorkingSpace WorkingSpace; /// /// Initializes a new instance of the struct. @@ -32,7 +50,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The blue component ranging between 0 and 1. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb(float r, float g, float b) - : this(new Vector3(r, g, b)) + : this(r, g, b, DefaultWorkingSpace) { } @@ -45,8 +63,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The rgb working space. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb(float r, float g, float b, RgbWorkingSpace workingSpace) - : this(new Vector3(r, g, b), workingSpace) { + this.R = r; + this.G = g; + this.B = b; + this.WorkingSpace = workingSpace; } /// @@ -66,51 +87,15 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The rgb working space. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb(Vector3 vector, RgbWorkingSpace workingSpace) - : this() { // Clamp to 0-1 range. - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + this.R = vector.X; + this.G = vector.Y; + this.B = vector.Z; this.WorkingSpace = workingSpace; } - /// - /// Gets the red component. - /// A value usually ranging between 0 and 1. - /// - public float R - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the green component. - /// A value usually ranging between 0 and 1. - /// - public float G - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the blue component. - /// A value usually ranging between 0 and 1. - /// - public float B - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - /// Gets the Rgb color space - /// - public RgbWorkingSpace WorkingSpace { get; } - - /// - public Vector3 Vector => this.backingVector; - /// /// Allows the implicit conversion of an instance of to a /// . @@ -140,33 +125,32 @@ namespace SixLabors.ImageSharp.ColorSpaces /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgb left, Rgb right) - { - return left.Equals(right); - } + public static bool operator ==(Rgb left, Rgb right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgb left, Rgb right) - { - return !left.Equals(right); - } + public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right); + + /// + /// Returns a new representing this instance. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector3 ToVector3() => new Vector3(this.R, this.G, this.B); /// public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.R.GetHashCode(); + hash = HashHelpers.Combine(hash, this.G.GetHashCode()); + return HashHelpers.Combine(hash, this.B.GetHashCode()); } /// @@ -178,27 +162,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is Rgb other && this.Equals(other); - } + public override bool Equals(object obj) => obj is Rgb other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Rgb other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(Rgb other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index 00533c6991..f684f598b0 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -13,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// /// - internal readonly struct YCbCr : IColorVector, IEquatable, IAlmostEquatable + internal readonly struct YCbCr : IEquatable { /// /// Vector which is used in clamping to the max value. @@ -21,9 +20,22 @@ namespace SixLabors.ImageSharp.ColorSpaces private static readonly Vector3 VectorMax = new Vector3(255F); /// - /// The backing vector for SIMD support. + /// Gets the Y luminance component. + /// A value ranging between 0 and 255. + /// + public readonly float Y; + + /// + /// Gets the Cb chroma component. + /// A value ranging between 0 and 255. + /// + public readonly float Cb; + + /// + /// Gets the Cr chroma component. + /// A value ranging between 0 and 255. /// - private readonly Vector3 backingVector; + public readonly float Cr; /// /// Initializes a new instance of the struct. @@ -44,82 +56,40 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr(Vector3 vector) { - this.backingVector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + this.Y = vector.X; + this.Cb = vector.Y; + this.Cr = vector.Z; } - /// - /// Gets the Y luminance component. - /// A value ranging between 0 and 255. - /// - public float Y - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.X; - } - - /// - /// Gets the Cb chroma component. - /// A value ranging between 0 and 255. - /// - public float Cb - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Y; - } - - /// - /// Gets the Cr chroma component. - /// A value ranging between 0 and 255. - /// - public float Cr - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.backingVector.Z; - } - - /// - public Vector3 Vector => this.backingVector; - /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// - public static bool operator ==(YCbCr left, YCbCr right) - { - return left.Equals(right); - } + public static bool operator ==(YCbCr left, YCbCr right) => left.Equals(right); /// /// Compares two objects for inequality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(YCbCr left, YCbCr right) - { - return !left.Equals(right); - } + public static bool operator !=(YCbCr left, YCbCr right) => !left.Equals(right); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { - return this.backingVector.GetHashCode(); + int hash = this.Y.GetHashCode(); + hash = HashHelpers.Combine(hash, this.Cb.GetHashCode()); + return HashHelpers.Combine(hash, this.Cr.GetHashCode()); } /// @@ -131,27 +101,15 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override bool Equals(object obj) - { - return obj is YCbCr other && this.Equals(other); - } + public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(YCbCr other) { - return this.backingVector.Equals(other.backingVector); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool AlmostEquals(YCbCr other, float precision) - { - var result = Vector3.Abs(this.backingVector - other.backingVector); - - return result.X <= precision - && result.Y <= precision - && result.Z <= precision; + return this.Y.Equals(other.Y) + && this.Cb.Equals(other.Cb) + && this.Cr.Equals(other.Cr); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs index 743653c413..b895ee9a46 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs @@ -17,228 +17,191 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class ColorSpaceEqualityTests { - internal static readonly Dictionary EmptyDataLookup = - new Dictionary - { - {nameof( CieLab), default(CieLab) }, - {nameof( CieLch), default(CieLch) }, - {nameof( CieLchuv), default(CieLchuv) }, - {nameof( CieLuv), default(CieLuv) }, - {nameof( CieXyz), default(CieXyz) }, - {nameof( CieXyy), default(CieXyy) }, - {nameof( Hsl), default(Hsl) }, - {nameof( HunterLab), default(HunterLab) }, - {nameof( Lms), default(Lms) }, - {nameof( LinearRgb), default(LinearRgb) }, - {nameof( Rgb), default(Rgb) }, - {nameof( YCbCr), default(YCbCr) } - }; - - public static readonly IEnumerable EmptyData = EmptyDataLookup.Select(x => new[] { x.Key }); - - public static readonly TheoryData EqualityData = - new TheoryData - { - { new CieLab(Vector3.One), new CieLab(Vector3.One), typeof(CieLab) }, - { new CieLch(Vector3.One), new CieLch(Vector3.One), typeof(CieLch) }, - { new CieLchuv(Vector3.One), new CieLchuv(Vector3.One), typeof(CieLchuv) }, - { new CieLuv(Vector3.One), new CieLuv(Vector3.One), typeof(CieLuv) }, - { new CieXyz(Vector3.One), new CieXyz(Vector3.One), typeof(CieXyz) }, - { new CieXyy(Vector3.One), new CieXyy(Vector3.One), typeof(CieXyy) }, - { new HunterLab(Vector3.One), new HunterLab(Vector3.One), typeof(HunterLab) }, - { new Lms(Vector3.One), new Lms(Vector3.One), typeof(Lms) }, - { new LinearRgb(Vector3.One), new LinearRgb(Vector3.One), typeof(LinearRgb) }, - { new Rgb(Vector3.One), new Rgb(Vector3.One), typeof(Rgb) }, - { new Hsl(Vector3.One), new Hsl(Vector3.One), typeof(Hsl) }, - { new Hsv(Vector3.One), new Hsv(Vector3.One), typeof(Hsv) }, - { new YCbCr(Vector3.One), new YCbCr(Vector3.One), typeof(YCbCr) }, - }; - - public static readonly TheoryData NotEqualityDataNulls = - new TheoryData - { - // Valid object against null - { new CieLab(Vector3.One), null, typeof(CieLab) }, - { new CieLch(Vector3.One), null, typeof(CieLch) }, - { new CieLchuv(Vector3.One), null, typeof(CieLchuv) }, - { new CieLuv(Vector3.One), null, typeof(CieLuv) }, - { new CieXyz(Vector3.One), null, typeof(CieXyz) }, - { new CieXyy(Vector3.One), null, typeof(CieXyy) }, - { new HunterLab(Vector3.One), null, typeof(HunterLab) }, - { new Lms(Vector3.One), null, typeof(Lms) }, - { new LinearRgb(Vector3.One), null, typeof(LinearRgb) }, - { new Rgb(Vector3.One), null, typeof(Rgb) }, - { new Hsl(Vector3.One), null, typeof(Hsl) }, - { new Hsv(Vector3.One), null, typeof(Hsv) }, - { new YCbCr(Vector3.One), null, typeof(YCbCr) }, - }; - - public static readonly TheoryData NotEqualityDataDifferentObjects = - new TheoryData - { - // Valid objects of different types but not equal - { new CieLab(Vector3.One), new CieLch(Vector3.Zero), null }, - { new CieLuv(Vector3.One), new CieLchuv(Vector3.Zero), null }, - { new CieXyz(Vector3.One), new HunterLab(Vector3.Zero), null }, - { new Rgb(Vector3.One), new LinearRgb(Vector3.Zero), null }, - { new Rgb(Vector3.One), new Lms(Vector3.Zero), null }, - { new Cmyk(Vector4.One), new Hsl(Vector3.Zero), null }, - { new YCbCr(Vector3.One), new CieXyy(Vector3.Zero), null }, - { new Hsv(Vector3.One), new Hsl(Vector3.Zero), null }, - }; - - public static readonly TheoryData NotEqualityData = - new TheoryData - { - // Valid objects of the same type but not equal - { new CieLab(Vector3.One), new CieLab(Vector3.Zero), typeof(CieLab) }, - { new CieLch(Vector3.One), new CieLch(Vector3.Zero), typeof(CieLch) }, - { new CieLchuv(Vector3.One), new CieLchuv(Vector3.Zero), typeof(CieLchuv) }, - { new CieLuv(Vector3.One), new CieLuv(Vector3.Zero), typeof(CieLuv) }, - { new CieXyz(Vector3.One), new CieXyz(Vector3.Zero), typeof(CieXyz) }, - { new CieXyy(Vector3.One), new CieXyy(Vector3.Zero), typeof(CieXyy) }, - { new HunterLab(Vector3.One), new HunterLab(Vector3.Zero), typeof(HunterLab) }, - { new Lms(Vector3.One), new Lms(Vector3.Zero), typeof(Lms) }, - { new LinearRgb(Vector3.One), new LinearRgb(Vector3.Zero), typeof(LinearRgb) }, - { new Rgb(Vector3.One), new Rgb(Vector3.Zero), typeof(Rgb) }, - { new Cmyk(Vector4.One), new Cmyk(Vector4.Zero), typeof(Cmyk) }, - { new Hsl(Vector3.One), new Hsl(Vector3.Zero), typeof(Hsl) }, - { new Hsv(Vector3.One), new Hsv(Vector3.Zero), typeof(Hsv) }, - { new YCbCr(Vector3.One), new YCbCr(Vector3.Zero), typeof(YCbCr) }, - }; - - public static readonly TheoryData AlmostEqualsData = - new TheoryData - { - { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), 0F }, - { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), .001F }, - { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), .0001F }, - { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), .0005F }, - { new CieLab(0F, 0F, 0F), new CieLab(0F, .001F, 0F), typeof(CieLab), .001F }, - { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, .0001F), typeof(CieLab), .0001F }, - { new CieLab(0F, 0F, 0F), new CieLab(.0005F, 0F, 0F), typeof(CieLab), .0005F }, - { new CieLch(0F, 0F, 0F), new CieLch(0F, .001F, 0F), typeof(CieLch), .001F }, - { new CieLchuv(0F, 0F, 0F), new CieLchuv(0F, .001F, 0F), typeof(CieLchuv), .001F }, - { new CieLuv(0F, 0F, 0F), new CieLuv(0F, .001F, 0F), typeof(CieLuv), .001F }, - { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380F), typeof(CieXyz), 0F }, - { new CieXyz(380F, 380F, 380F), new CieXyz(380.001F, 380F, 380F), typeof(CieXyz), .01F }, - { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380.001F, 380F), typeof(CieXyz), .01F }, - { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380.001F), typeof(CieXyz), .01F }, - { new Cmyk(1, 1, 1, 1), new Cmyk(1, 1, 1, .99F), typeof(Cmyk), .01F }, - { new YCbCr(255F, 128F, 128F), new YCbCr(255F, 128F, 128.001F), typeof(YCbCr), .01F }, - { new Hsv(0F, 0F, 0F), new Hsv(0F, 0F, 0F), typeof(Hsv), 0F }, - { new Hsl(0F, 0F, 0F), new Hsl(0F, 0F, 0F), typeof(Hsl), 0F }, - }; - - public static readonly TheoryData AlmostNotEqualsData = - new TheoryData - { - { new CieLab(0F, 0F, 0F), new CieLab(0.1F, 0F, 0F), typeof(CieLab), .001F }, - { new CieLab(0F, 0F, 0F), new CieLab(0F, 0.1F, 0F), typeof(CieLab), .001F }, - { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0.1F), typeof(CieLab), .001F }, - { new CieXyz(380F, 380F, 380F), new CieXyz(380.1F, 380F, 380F), typeof(CieXyz), .001F }, - { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380.1F, 380F), typeof(CieXyz), .001F }, - { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380.1F), typeof(CieXyz), .001F }, - }; - - [Theory] - [MemberData(nameof(EmptyData))] - public void Vector_Equals_WhenTrue(string color) - { - IColorVector colorVector = EmptyDataLookup[color]; - // Act - bool equal = colorVector.Vector.Equals(Vector3.Zero); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void Equals_WhenTrue(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataNulls))] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - [MemberData(nameof(NotEqualityData))] - public void Equals_WhenFalse(object first, object second, Type type) - { - // Act - bool equal = first.Equals(second); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void GetHashCode_WhenEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityDataDifferentObjects))] - public void GetHashCode_WhenNotEqual(object first, object second, Type type) - { - // Act - bool equal = first.GetHashCode() == second.GetHashCode(); - - // Assert - Assert.False(equal); - } - - [Theory] - [MemberData(nameof(EqualityData))] - public void GenericEquals_WhenTrue(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.True(equal); - } - - [Theory] - [MemberData(nameof(NotEqualityData))] - public void GenericEquals_WhenFalse(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic equal = firstObject.Equals(secondObject); - - // Assert - Assert.False(equal); - } - - // TODO:Disabled due to RuntypeBinder errors while structs are internal + //internal static readonly Dictionary EmptyDataLookup = + // new Dictionary + // { + // {nameof( CieLab), default(CieLab) }, + // {nameof( CieLch), default(CieLch) }, + // {nameof( CieLchuv), default(CieLchuv) }, + // {nameof( CieLuv), default(CieLuv) }, + // {nameof( CieXyz), default(CieXyz) }, + // {nameof( CieXyy), default(CieXyy) }, + // {nameof( Hsl), default(Hsl) }, + // {nameof( HunterLab), default(HunterLab) }, + // {nameof( Lms), default(Lms) }, + // {nameof( LinearRgb), default(LinearRgb) }, + // {nameof( Rgb), default(Rgb) }, + // {nameof( YCbCr), default(YCbCr) } + // }; + + //public static readonly IEnumerable EmptyData = EmptyDataLookup.Select(x => new[] { x.Key }); + + //public static readonly TheoryData EqualityData = + // new TheoryData + // { + // { new CieLab(Vector3.One), new CieLab(Vector3.One), typeof(CieLab) }, + // { new CieLch(Vector3.One), new CieLch(Vector3.One), typeof(CieLch) }, + // { new CieLchuv(Vector3.One), new CieLchuv(Vector3.One), typeof(CieLchuv) }, + // { new CieLuv(Vector3.One), new CieLuv(Vector3.One), typeof(CieLuv) }, + // { new CieXyz(Vector3.One), new CieXyz(Vector3.One), typeof(CieXyz) }, + // { new CieXyy(Vector3.One), new CieXyy(Vector3.One), typeof(CieXyy) }, + // { new HunterLab(Vector3.One), new HunterLab(Vector3.One), typeof(HunterLab) }, + // { new Lms(Vector3.One), new Lms(Vector3.One), typeof(Lms) }, + // { new LinearRgb(Vector3.One), new LinearRgb(Vector3.One), typeof(LinearRgb) }, + // { new Rgb(Vector3.One), new Rgb(Vector3.One), typeof(Rgb) }, + // { new Hsl(Vector3.One), new Hsl(Vector3.One), typeof(Hsl) }, + // { new Hsv(Vector3.One), new Hsv(Vector3.One), typeof(Hsv) }, + // { new YCbCr(Vector3.One), new YCbCr(Vector3.One), typeof(YCbCr) }, + // }; + + //public static readonly TheoryData NotEqualityDataNulls = + // new TheoryData + // { + // // Valid object against null + // { new CieLab(Vector3.One), null, typeof(CieLab) }, + // { new CieLch(Vector3.One), null, typeof(CieLch) }, + // { new CieLchuv(Vector3.One), null, typeof(CieLchuv) }, + // { new CieLuv(Vector3.One), null, typeof(CieLuv) }, + // { new CieXyz(Vector3.One), null, typeof(CieXyz) }, + // { new CieXyy(Vector3.One), null, typeof(CieXyy) }, + // { new HunterLab(Vector3.One), null, typeof(HunterLab) }, + // { new Lms(Vector3.One), null, typeof(Lms) }, + // { new LinearRgb(Vector3.One), null, typeof(LinearRgb) }, + // { new Rgb(Vector3.One), null, typeof(Rgb) }, + // { new Hsl(Vector3.One), null, typeof(Hsl) }, + // { new Hsv(Vector3.One), null, typeof(Hsv) }, + // { new YCbCr(Vector3.One), null, typeof(YCbCr) }, + // }; + + //public static readonly TheoryData NotEqualityDataDifferentObjects = + // new TheoryData + // { + // // Valid objects of different types but not equal + // { new CieLab(Vector3.One), new CieLch(Vector3.Zero), null }, + // { new CieLuv(Vector3.One), new CieLchuv(Vector3.Zero), null }, + // { new CieXyz(Vector3.One), new HunterLab(Vector3.Zero), null }, + // { new Rgb(Vector3.One), new LinearRgb(Vector3.Zero), null }, + // { new Rgb(Vector3.One), new Lms(Vector3.Zero), null }, + // { new Cmyk(Vector4.One), new Hsl(Vector3.Zero), null }, + // { new YCbCr(Vector3.One), new CieXyy(Vector3.Zero), null }, + // { new Hsv(Vector3.One), new Hsl(Vector3.Zero), null }, + // }; + + //public static readonly TheoryData NotEqualityData = + // new TheoryData + // { + // // Valid objects of the same type but not equal + // { new CieLab(Vector3.One), new CieLab(Vector3.Zero), typeof(CieLab) }, + // { new CieLch(Vector3.One), new CieLch(Vector3.Zero), typeof(CieLch) }, + // { new CieLchuv(Vector3.One), new CieLchuv(Vector3.Zero), typeof(CieLchuv) }, + // { new CieLuv(Vector3.One), new CieLuv(Vector3.Zero), typeof(CieLuv) }, + // { new CieXyz(Vector3.One), new CieXyz(Vector3.Zero), typeof(CieXyz) }, + // { new CieXyy(Vector3.One), new CieXyy(Vector3.Zero), typeof(CieXyy) }, + // { new HunterLab(Vector3.One), new HunterLab(Vector3.Zero), typeof(HunterLab) }, + // { new Lms(Vector3.One), new Lms(Vector3.Zero), typeof(Lms) }, + // { new LinearRgb(Vector3.One), new LinearRgb(Vector3.Zero), typeof(LinearRgb) }, + // { new Rgb(Vector3.One), new Rgb(Vector3.Zero), typeof(Rgb) }, + // { new Cmyk(Vector4.One), new Cmyk(Vector4.Zero), typeof(Cmyk) }, + // { new Hsl(Vector3.One), new Hsl(Vector3.Zero), typeof(Hsl) }, + // { new Hsv(Vector3.One), new Hsv(Vector3.Zero), typeof(Hsv) }, + // { new YCbCr(Vector3.One), new YCbCr(Vector3.Zero), typeof(YCbCr) }, + // }; + + //public static readonly TheoryData AlmostEqualsData = + // new TheoryData + // { + // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), 0F }, + // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), .001F }, + // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), .0001F }, + // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), .0005F }, + // { new CieLab(0F, 0F, 0F), new CieLab(0F, .001F, 0F), typeof(CieLab), .001F }, + // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, .0001F), typeof(CieLab), .0001F }, + // { new CieLab(0F, 0F, 0F), new CieLab(.0005F, 0F, 0F), typeof(CieLab), .0005F }, + // { new CieLch(0F, 0F, 0F), new CieLch(0F, .001F, 0F), typeof(CieLch), .001F }, + // { new CieLchuv(0F, 0F, 0F), new CieLchuv(0F, .001F, 0F), typeof(CieLchuv), .001F }, + // { new CieLuv(0F, 0F, 0F), new CieLuv(0F, .001F, 0F), typeof(CieLuv), .001F }, + // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380F), typeof(CieXyz), 0F }, + // { new CieXyz(380F, 380F, 380F), new CieXyz(380.001F, 380F, 380F), typeof(CieXyz), .01F }, + // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380.001F, 380F), typeof(CieXyz), .01F }, + // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380.001F), typeof(CieXyz), .01F }, + // { new Cmyk(1, 1, 1, 1), new Cmyk(1, 1, 1, .99F), typeof(Cmyk), .01F }, + // { new YCbCr(255F, 128F, 128F), new YCbCr(255F, 128F, 128.001F), typeof(YCbCr), .01F }, + // { new Hsv(0F, 0F, 0F), new Hsv(0F, 0F, 0F), typeof(Hsv), 0F }, + // { new Hsl(0F, 0F, 0F), new Hsl(0F, 0F, 0F), typeof(Hsl), 0F }, + // }; + + //public static readonly TheoryData AlmostNotEqualsData = + // new TheoryData + // { + // { new CieLab(0F, 0F, 0F), new CieLab(0.1F, 0F, 0F), typeof(CieLab), .001F }, + // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0.1F, 0F), typeof(CieLab), .001F }, + // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0.1F), typeof(CieLab), .001F }, + // { new CieXyz(380F, 380F, 380F), new CieXyz(380.1F, 380F, 380F), typeof(CieXyz), .001F }, + // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380.1F, 380F), typeof(CieXyz), .001F }, + // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380.1F), typeof(CieXyz), .001F }, + // }; + + //[Theory] + //[MemberData(nameof(EmptyData))] + //public void Vector_Equals_WhenTrue(string color) + //{ + // IColorVector colorVector = EmptyDataLookup[color]; + // // Act + // bool equal = colorVector.Vector.Equals(Vector3.Zero); + + // // Assert + // Assert.True(equal); + //} + //[Theory] //[MemberData(nameof(EqualityData))] - //public void EqualityOperator(object first, object second, Type type) + //public void Equals_WhenTrue(object first, object second, Type type) + //{ + // // Act + // bool equal = first.Equals(second); + + // // Assert + // Assert.True(equal); + //} + + //[Theory] + //[MemberData(nameof(NotEqualityDataNulls))] + //[MemberData(nameof(NotEqualityDataDifferentObjects))] + //[MemberData(nameof(NotEqualityData))] + //public void Equals_WhenFalse(object first, object second, Type type) + //{ + // // Act + // bool equal = first.Equals(second); + + // // Assert + // Assert.False(equal); + //} + + //[Theory] + //[MemberData(nameof(EqualityData))] + //public void GetHashCode_WhenEqual(object first, object second, Type type) + //{ + // // Act + // bool equal = first.GetHashCode() == second.GetHashCode(); + + // // Assert + // Assert.True(equal); + //} + + //[Theory] + //[MemberData(nameof(NotEqualityDataDifferentObjects))] + //public void GetHashCode_WhenNotEqual(object first, object second, Type type) + //{ + // // Act + // bool equal = first.GetHashCode() == second.GetHashCode(); + + // // Assert + // Assert.False(equal); + //} + + //[Theory] + //[MemberData(nameof(EqualityData))] + //public void GenericEquals_WhenTrue(object first, object second, Type type) //{ // // Arrange // // Cast to the known object types, this is so that we can hit the @@ -248,34 +211,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // dynamic secondObject = Convert.ChangeType(second, type); // // Act - // dynamic equal = firstObject == secondObject; + // dynamic equal = firstObject.Equals(secondObject); // // Assert // Assert.True(equal); //} - [Theory] - [MemberData(nameof(NotEqualityData))] - public void Operator_WhenTrue(object first, object second, Type type) - { - // Arrange - // Cast to the known object types, this is so that we can hit the - // equality operator on the concrete type, otherwise it goes to the - // default "object" one :) - dynamic firstObject = Convert.ChangeType(first, type); - dynamic secondObject = Convert.ChangeType(second, type); - - // Act - dynamic notEqual = firstObject != secondObject; - - // Assert - Assert.True(notEqual); - } - - // TODO:Disabled due to RuntypeBinder errors while structs are internal //[Theory] - //[MemberData(nameof(AlmostEqualsData))] - //public void AlmostEquals(object first, object second, Type type, float precision) + //[MemberData(nameof(NotEqualityData))] + //public void GenericEquals_WhenFalse(object first, object second, Type type) //{ // // Arrange // // Cast to the known object types, this is so that we can hit the @@ -285,16 +229,34 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // dynamic secondObject = Convert.ChangeType(second, type); // // Act - // dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision); + // dynamic equal = firstObject.Equals(secondObject); // // Assert - // Assert.True(almostEqual); + // Assert.False(equal); //} - // TODO:Disabled due to RuntypeBinder errors while structs are internal + //// TODO:Disabled due to RuntypeBinder errors while structs are internal + ////[Theory] + ////[MemberData(nameof(EqualityData))] + ////public void EqualityOperator(object first, object second, Type type) + ////{ + //// // Arrange + //// // Cast to the known object types, this is so that we can hit the + //// // equality operator on the concrete type, otherwise it goes to the + //// // default "object" one :) + //// dynamic firstObject = Convert.ChangeType(first, type); + //// dynamic secondObject = Convert.ChangeType(second, type); + + //// // Act + //// dynamic equal = firstObject == secondObject; + + //// // Assert + //// Assert.True(equal); + ////} + //[Theory] - //[MemberData(nameof(AlmostNotEqualsData))] - //public void AlmostNotEquals(object first, object second, Type type, float precision) + //[MemberData(nameof(NotEqualityData))] + //public void Operator_WhenTrue(object first, object second, Type type) //{ // // Arrange // // Cast to the known object types, this is so that we can hit the @@ -304,10 +266,48 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // dynamic secondObject = Convert.ChangeType(second, type); // // Act - // dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision); + // dynamic notEqual = firstObject != secondObject; // // Assert - // Assert.False(almostEqual); + // Assert.True(notEqual); //} + + //// TODO:Disabled due to RuntypeBinder errors while structs are internal + ////[Theory] + ////[MemberData(nameof(AlmostEqualsData))] + ////public void AlmostEquals(object first, object second, Type type, float precision) + ////{ + //// // Arrange + //// // Cast to the known object types, this is so that we can hit the + //// // equality operator on the concrete type, otherwise it goes to the + //// // default "object" one :) + //// dynamic firstObject = Convert.ChangeType(first, type); + //// dynamic secondObject = Convert.ChangeType(second, type); + + //// // Act + //// dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision); + + //// // Assert + //// Assert.True(almostEqual); + ////} + + //// TODO:Disabled due to RuntypeBinder errors while structs are internal + ////[Theory] + ////[MemberData(nameof(AlmostNotEqualsData))] + ////public void AlmostNotEquals(object first, object second, Type type, float precision) + ////{ + //// // Arrange + //// // Cast to the known object types, this is so that we can hit the + //// // equality operator on the concrete type, otherwise it goes to the + //// // default "object" one :) + //// dynamic firstObject = Convert.ChangeType(first, type); + //// dynamic secondObject = Convert.ChangeType(second, type); + + //// // Act + //// dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision); + + //// // Assert + //// Assert.False(almostEqual); + ////} } } From 897cbe13a06834f12bef126613973ac6fa7ca195 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 14 Jul 2018 22:42:15 +1000 Subject: [PATCH 013/185] Add bulk CieXyy transforms --- .../Conversion/ColorSpaceConverter.CieXyy.cs | 276 ++++++++++++++++++ 1 file changed, 276 insertions(+) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index 4b14f65bc8..464c5ff919 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -24,6 +27,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -36,6 +60,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -48,6 +93,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -60,6 +126,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -70,6 +157,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CieXyzAndCieXyyConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -82,6 +190,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -94,6 +223,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -106,6 +256,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -118,6 +289,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -130,6 +322,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -142,6 +355,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -154,6 +388,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } + /// /// Converts a into a /// @@ -165,5 +420,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyy(xyzColor); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyy destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyy dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyy(sp); + } + } } } \ No newline at end of file From 2cbb34a080d4891ceed8230b9f60b1cc0e44d42b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 15 Jul 2018 17:07:30 +1000 Subject: [PATCH 014/185] Add bulk ToCieXyz --- .../Conversion/ColorSpaceConverter.CieXyz.cs | 276 ++++++++++++++++++ 1 file changed, 276 insertions(+) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 80d084ae6c..6ecb33ffc9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -36,6 +39,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return adapted; } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -50,6 +74,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyz(labColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -64,6 +109,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyz(luvColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -82,6 +148,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return adapted; } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -93,6 +180,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CieXyzAndCieXyyConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -106,6 +214,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyz(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -119,6 +248,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyz(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -132,6 +282,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyz(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -150,6 +321,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return adapted; } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -167,6 +359,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion : this.Adapt(unadapted, color.WorkingSpace.WhitePoint); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -178,6 +391,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.cachedCieXyzAndLmsConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -190,6 +424,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyz(linear); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Converts a into a /// @@ -203,6 +458,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCieXyz(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCieXyz(sp); + } + } + /// /// Gets the correct converter for the given rgb working space. /// From 5c6568ae6f0e37f000b0f38853dac74c022d09a1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 15 Jul 2018 22:49:50 +1000 Subject: [PATCH 015/185] Add bulk ToCmyk --- .../Conversion/ColorSpaceConverter.Cmyk.cs | 276 ++++++++++++++++++ 1 file changed, 276 insertions(+) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index 07e9bb94b1..f8628e39b6 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -24,6 +27,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCmyk(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -36,6 +60,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCmyk(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -48,6 +93,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCmyk(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -60,6 +126,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCmyk(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -72,6 +159,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCmyk(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -84,6 +192,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CmykAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -96,6 +225,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CmykAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -108,6 +258,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CmykAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -120,6 +291,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCmyk(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -132,6 +324,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CmykAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -144,6 +357,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToCmyk(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -154,6 +388,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CmykAndRgbConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } + /// /// Converts a into a /// @@ -165,5 +420,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CmykAndRgbConverter.Convert(rgb); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref Cmyk destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref Cmyk dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToCmyk(sp); + } + } } } \ No newline at end of file From 1e9061d986ea22acda6d96277bdbdac0b6e5acaa Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 15 Jul 2018 23:15:02 +1000 Subject: [PATCH 016/185] Add bulk ToHsl, ToHsv --- .../Conversion/ColorSpaceConverter.Hsl.cs | 276 ++++++++++++++++++ .../Conversion/ColorSpaceConverter.Hsv.cs | 276 ++++++++++++++++++ 2 files changed, 552 insertions(+) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index 1d6529b892..8832be9174 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -24,6 +27,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsl(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -36,6 +60,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsl(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -48,6 +93,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsl(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -60,6 +126,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsl(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -72,6 +159,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsl(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -84,6 +192,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HslAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -96,6 +225,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HslAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -108,6 +258,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HslAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -120,6 +291,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsl(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -132,6 +324,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HslAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -144,6 +357,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsl(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -154,6 +388,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HslAndRgbConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } + /// /// Converts a into a /// @@ -165,5 +420,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HslAndRgbConverter.Convert(rgb); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsl destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsl dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsl(sp); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index 9b623a621d..8269014276 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -24,6 +27,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -36,6 +60,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -48,6 +93,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -60,6 +126,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -72,6 +159,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -84,6 +192,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HsvAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -96,6 +225,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HsvAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -108,6 +258,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HsvAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -120,6 +291,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -132,6 +324,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HsvAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -144,6 +357,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHsv(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -154,6 +388,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HsvAndRgbConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } + /// /// Converts a into a /// @@ -165,5 +420,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HsvAndRgbConverter.Convert(rgb); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref Hsv destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref Hsv dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHsv(sp); + } + } } } \ No newline at end of file From 53566333c53b76ebb20df0954e045c8fe22923bc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 16 Jul 2018 00:14:03 +1000 Subject: [PATCH 017/185] Fix tests --- src/ImageSharp/ColorSpaces/Cmyk.cs | 4 +- src/ImageSharp/ColorSpaces/Rgb.cs | 7 +-- .../ApproximateColorspaceComparer.cs | 46 +++++++++++++++++++ .../Formats/Jpg/JpegColorConverterTests.cs | 15 +++--- 4 files changed, 61 insertions(+), 11 deletions(-) create mode 100644 tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index 711e9867f7..1fa097d9e8 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -58,8 +58,8 @@ namespace SixLabors.ImageSharp.ColorSpaces { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); this.C = vector.X; - this.Y = vector.Y; - this.M = vector.Z; + this.M = vector.Y; + this.Y = vector.Z; this.K = vector.W; } diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 7c8437d6e2..8faf4f2b59 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -64,9 +64,10 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb(float r, float g, float b, RgbWorkingSpace workingSpace) { - this.R = r; - this.G = g; - this.B = b; + // Clamp to 0-1 range. + this.R = r.Clamp(0, 1F); + this.G = g.Clamp(0, 1F); + this.B = b.Clamp(0, 1F); this.WorkingSpace = workingSpace; } diff --git a/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs new file mode 100644 index 0000000000..28e2fdf82b --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs @@ -0,0 +1,46 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Collections.Generic; +using SixLabors.ImageSharp.ColorSpaces; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Allows the approximate comparison of colorspace component values. + /// + internal class ApproximateColorSpaceComparer : IEqualityComparer + { + private readonly float Epsilon; + + /// + /// Initializes a new instance of the class. + /// + /// The comparison error difference epsilon to use. + public ApproximateColorSpaceComparer(float epsilon = 1F) + { + this.Epsilon = epsilon; + } + + /// + public bool Equals(Rgb x, Rgb y) + { + return this.Equals(x.R, y.R) + && this.Equals(x.G, y.G) + && this.Equals(x.B, y.B); + } + + /// + public int GetHashCode(Rgb obj) + { + return obj.GetHashCode(); + } + + private bool Equals(float x, float y) + { + float d = x - y; + + return d >= -this.Epsilon && d <= this.Epsilon; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index aed650b8e9..94b3a85834 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -8,6 +8,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; +using SixLabors.ImageSharp.Tests.Colorspaces; using SixLabors.Memory; using Xunit; @@ -17,7 +18,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { public class JpegColorConverterTests { - private const float Precision = 0.1f / 255; + private const float Precision = 0.1F / 255; + + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(Precision); public static readonly TheoryData CommonConversionData = new TheoryData @@ -59,7 +62,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); var expected = ColorSpaceConverter.ToRgb(ycbcr); - Assert.True(actual.AlmostEquals(expected, Precision), $"{actual} != {expected}"); + Assert.Equal(expected, actual, ColorSpaceComparer); Assert.Equal(1, rgba.W); } @@ -182,7 +185,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); var expected = new Rgb(v.X, v.Y, v.Z); - Assert.True(actual.AlmostEquals(expected, Precision)); + Assert.Equal(expected, actual); Assert.Equal(1, rgba.W); } } @@ -204,7 +207,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); var expected = new Rgb(y / 255F, y / 255F, y / 255F); - Assert.True(actual.AlmostEquals(expected, Precision)); + Assert.Equal(expected, actual, ColorSpaceComparer); Assert.Equal(1, rgba.W); } } @@ -228,7 +231,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); var expected = new Rgb(r / 255F, g / 255F, b / 255F); - Assert.True(actual.AlmostEquals(expected, Precision)); + Assert.Equal(expected, actual, ColorSpaceComparer); Assert.Equal(1, rgba.W); } } @@ -266,7 +269,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg var actual = new Rgb(rgba.X, rgba.Y, rgba.Z); var expected = new Rgb(v.X, v.Y, v.Z); - Assert.True(actual.AlmostEquals(expected, Precision)); + Assert.Equal(expected, actual, ColorSpaceComparer); Assert.Equal(1, rgba.W); } } From db6c8f39fcaff0a1cc21066eb2e3e67581491aee Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 23 Jul 2018 08:53:21 +0100 Subject: [PATCH 018/185] Add bulk ToHunterLab, ToLinearRgb, and ToLms --- .../ColorSpaceConverter.HunterLab.cs | 276 ++++++++++++++++++ .../ColorSpaceConverter.LinearRgb.cs | 276 ++++++++++++++++++ .../Conversion/ColorSpaceConverter.Lms.cs | 276 ++++++++++++++++++ 3 files changed, 828 insertions(+) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index c5e383e304..27c5589de4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -21,6 +24,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -32,6 +56,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -43,6 +88,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -54,6 +120,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -65,6 +152,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -81,6 +189,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return new CieXyzToHunterLabConverter(this.TargetHunterLabWhitePoint).Convert(adapted); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -92,6 +221,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -103,6 +253,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -114,6 +285,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -125,6 +317,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -136,6 +349,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -147,6 +381,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToHunterLab(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } + /// /// Converts a into a /// @@ -157,5 +412,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion var xyzColor = this.ToCieXyz(color); return this.ToHunterLab(xyzColor); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref HunterLab destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref HunterLab dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToHunterLab(sp); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index e203ae0e5b..2f65841bc2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -25,6 +28,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -36,6 +60,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -47,6 +92,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -58,6 +124,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -69,6 +156,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -86,6 +194,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return xyzConverter.Convert(adapted); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -97,6 +226,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -108,6 +258,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -119,6 +290,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -130,6 +322,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -141,6 +354,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -152,6 +386,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return RgbToLinearRgbConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Converts a into a /// @@ -163,6 +418,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLinearRgb(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref LinearRgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref LinearRgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLinearRgb(sp); + } + } + /// /// Gets the correct converter for the given rgb working space. /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index b7ef15a02b..4f1e4b5a11 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -1,5 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { @@ -19,6 +22,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -30,6 +54,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -41,6 +86,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -52,6 +118,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -63,6 +150,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -73,6 +181,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.cachedCieXyzAndLmsConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -84,6 +213,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -95,6 +245,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -106,6 +277,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -117,6 +309,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -128,6 +341,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -139,6 +373,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToLms(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } + /// /// Converts a into a /// @@ -149,5 +404,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion var xyzColor = this.ToCieXyz(color); return this.ToLms(xyzColor); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref Lms destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref Lms dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToLms(sp); + } + } } } \ No newline at end of file From 28f793d5e8bbace345af2db084cfd00dd19c8115 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 26 Jul 2018 19:17:35 +0100 Subject: [PATCH 019/185] Begin colorspace test cleanup. --- .../Conversion/ColorSpaceConverter.Lms.cs | 1 + .../Conversion/ColorSpaceConverter.Rgb.cs | 276 +++++++++++ .../Conversion/ColorSpaceConverter.YCbCr.cs | 255 +++++++++- .../ApproximateColorspaceComparer.cs | 124 ++++- .../CieLabAndCieLchConversionTests.cs | 18 +- .../CieLuvAndCieLchuvConversionTests.cs | 18 +- .../CieXyzAndCieLabConversionTest.cs | 17 +- .../CieXyzAndCieLuvConversionTest.cs | 17 +- .../CieXyzAndCieXyyConversionTest.cs | 17 +- .../CieXyzAndHunterLabConversionTest.cs | 26 +- .../Colorspaces/CieXyzAndLmsConversionTest.cs | 18 +- .../Colorspaces/ColorConverterAdaptTest.cs | 65 +-- .../Colorspaces/ColorSpaceEqualityTests.cs | 445 ++++++------------ .../Formats/Jpg/JpegColorConverterTests.cs | 2 +- 14 files changed, 880 insertions(+), 419 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index 4f1e4b5a11..052aeb6d15 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -1,5 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. + using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index bea6e08019..5ef7934481 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -23,6 +26,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -34,6 +58,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -45,6 +90,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLchuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLchuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -56,6 +122,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -67,6 +154,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -81,6 +189,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToRgb(linear); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -92,6 +221,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return CmykAndRgbConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -103,6 +253,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HsvAndRgbConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -114,6 +285,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return HslAndRgbConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -125,6 +317,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -136,6 +349,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return LinearRgbToRgbConverter.Convert(color); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -147,6 +381,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToRgb(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } + /// /// Converts a into a /// @@ -160,5 +415,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion // Adaptation return this.Adapt(rgb); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref YCbCr sourceRef = ref MemoryMarshal.GetReference(source); + ref Rgb destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref YCbCr sp = ref Unsafe.Add(ref sourceRef, i); + ref Rgb dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToRgb(sp); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 4726d3d494..4bb3db82c9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -24,6 +27,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToYCbCr(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLab sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLab sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -37,15 +61,24 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - /// Converts a into a + /// Performs the bulk conversion from into /// - /// The color to convert. - /// The - public YCbCr ToYCbCr(in CieLchuv color) + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) { - var xyzColor = this.ToCieXyz(color); + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); - return this.ToYCbCr(xyzColor); + ref CieLch sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLch sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } } /// @@ -60,6 +93,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToYCbCr(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieLuv sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieLuv sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -72,6 +126,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToYCbCr(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyy sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyy sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -84,6 +159,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return YCbCrAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -96,6 +192,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return YCbCrAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Cmyk sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Cmyk sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -108,6 +225,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return YCbCrAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsl sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsl sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -120,6 +258,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return YCbCrAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Hsv sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Hsv sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -132,6 +291,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToYCbCr(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref HunterLab sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref HunterLab sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -144,6 +324,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return YCbCrAndRgbConverter.Convert(rgb); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref LinearRgb sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref LinearRgb sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -156,6 +357,27 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion return this.ToYCbCr(xyzColor); } + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Lms sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Lms sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } + /// /// Converts a into a /// @@ -165,5 +387,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { return YCbCrAndRgbConverter.Convert(color); } + + /// + /// Performs the bulk conversion from into + /// + /// The span to the source colors + /// The span to the destination colors + /// The number of colors to convert. + public void Convert(Span source, Span destination, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + ref Rgb sourceRef = ref MemoryMarshal.GetReference(source); + ref YCbCr destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref Rgb sp = ref Unsafe.Add(ref sourceRef, i); + ref YCbCr dp = ref Unsafe.Add(ref destRef, i); + dp = this.ToYCbCr(sp); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs index 28e2fdf82b..faba575de0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs @@ -9,7 +9,16 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// /// Allows the approximate comparison of colorspace component values. /// - internal class ApproximateColorSpaceComparer : IEqualityComparer + internal class ApproximateColorSpaceComparer : + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer { private readonly float Epsilon; @@ -36,10 +45,121 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces return obj.GetHashCode(); } + /// + public bool Equals(CieLab x, CieLab y) + { + return this.Equals(x.L, y.L) + && this.Equals(x.A, y.A) + && this.Equals(x.B, y.B); + } + + /// + public int GetHashCode(CieLab obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(CieLch x, CieLch y) + { + return this.Equals(x.L, y.L) + && this.Equals(x.C, y.C) + && this.Equals(x.H, y.H); + } + + /// + public int GetHashCode(CieLch obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(CieLchuv x, CieLchuv y) + { + return this.Equals(x.L, y.L) + && this.Equals(x.C, y.C) + && this.Equals(x.H, y.H); + } + + /// + public int GetHashCode(CieLchuv obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(CieLuv x, CieLuv y) + { + return this.Equals(x.L, y.L) + && this.Equals(x.U, y.U) + && this.Equals(x.V, y.V); + } + + /// + public int GetHashCode(CieLuv obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(CieXyz x, CieXyz y) + { + return this.Equals(x.X, y.X) + && this.Equals(x.Y, y.Y) + && this.Equals(x.Z, y.Z); + } + + /// + public int GetHashCode(CieXyz obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(CieXyy x, CieXyy y) + { + return this.Equals(x.X, y.X) + && this.Equals(x.Y, y.Y) + && this.Equals(x.Yl, y.Yl); + } + + /// + public int GetHashCode(CieXyy obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(HunterLab x, HunterLab y) + { + return this.Equals(x.L, y.L) + && this.Equals(x.A, y.A) + && this.Equals(x.B, y.B); + } + + /// + public int GetHashCode(HunterLab obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(Lms x, Lms y) + { + return this.Equals(x.L, y.L) + && this.Equals(x.M, y.M) + && this.Equals(x.S, y.S); + } + + /// + public int GetHashCode(Lms obj) + { + return obj.GetHashCode(); + } + private bool Equals(float x, float y) { float d = x - y; - return d >= -this.Epsilon && d <= this.Epsilon; } } diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs index 299b9e9e5b..0425d8e209 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -17,8 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class CieLabAndCieLchConversionTests { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); - + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); /// @@ -37,14 +35,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new CieLch(l, c, h); + var expected = new CieLab(l2, a, b); // Act - var output = Converter.ToCieLab(input); + var actual = Converter.ToCieLab(input); // Assert - Assert.Equal(l2, output.L, FloatRoundingComparer); - Assert.Equal(a, output.A, FloatRoundingComparer); - Assert.Equal(b, output.B, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } /// @@ -63,14 +60,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new CieLab(l, a, b); + var expected = new CieLch(l2, c, h); // Act - var output = Converter.ToCieLch(input); + var actual = Converter.ToCieLch(input); // Assert - Assert.Equal(l2, output.L, FloatRoundingComparer); - Assert.Equal(c, output.C, FloatRoundingComparer); - Assert.Equal(h, output.H, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs index cbcddcfe50..1bff994e1d 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -17,8 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class CieLuvAndCieLchuvuvConversionTests { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); - + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); /// @@ -37,14 +35,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new CieLchuv(l, c, h); + var expected = new CieLuv(l2, u, v); // Act - CieLuv output = Converter.ToCieLuv(input); + var actual = Converter.ToCieLuv(input); // Assert - Assert.Equal(l2, output.L, FloatRoundingComparer); - Assert.Equal(u, output.U, FloatRoundingComparer); - Assert.Equal(v, output.V, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } /// @@ -64,14 +61,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new CieLuv(l, u, v); + var expected = new CieLchuv(l2, c, h); // Act - CieLchuv output = Converter.ToCieLchuv(input); + var actual = Converter.ToCieLchuv(input); // Assert - Assert.Equal(l2, output.L, FloatRoundingComparer); - Assert.Equal(c, output.C, FloatRoundingComparer); - Assert.Equal(h, output.H, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs index 1be3ac9713..bf582650bc 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -17,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class CieXyzAndCieLabConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); /// /// Tests conversion from to (). @@ -36,14 +35,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new CieLab(l, a, b, Illuminants.D65); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var expected = new CieXyz(x, y, z); // Act - var output = converter.ToCieXyz(input); + var actual = converter.ToCieXyz(input); // Assert - Assert.Equal(x, output.X, FloatRoundingComparer); - Assert.Equal(y, output.Y, FloatRoundingComparer); - Assert.Equal(z, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } /// @@ -61,14 +59,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new CieXyz(x, y, z); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var expected = new CieLab(l, a, b); // Act - var output = converter.ToCieLab(input); + var actual = converter.ToCieLab(input); // Assert - Assert.Equal(l, output.L, FloatRoundingComparer); - Assert.Equal(a, output.A, FloatRoundingComparer); - Assert.Equal(b, output.B, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs index 46f4f15b8a..66150fe040 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -17,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class CieXyzAndCieLuvConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); /// /// Tests conversion from to (). @@ -35,14 +34,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new CieLuv(l, u, v, Illuminants.D65); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var expected = new CieXyz(x, y, z); // Act - CieXyz output = converter.ToCieXyz(input); + var actual = converter.ToCieXyz(input); // Assert - Assert.Equal(x, output.X, FloatRoundingComparer); - Assert.Equal(y, output.Y, FloatRoundingComparer); - Assert.Equal(z, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } /// @@ -60,14 +58,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new CieXyz(x, y, z); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var expected = new CieLuv(l, u, v); // Act - CieLuv output = converter.ToCieLuv(input); + var actual = converter.ToCieLuv(input); // Assert - Assert.Equal(l, output.L, FloatRoundingComparer); - Assert.Equal(u, output.U, FloatRoundingComparer); - Assert.Equal(v, output.V, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs index d461acd56c..46bdf80709 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs @@ -17,8 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class CieXyzAndCieXyyConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); - + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); [Theory] @@ -29,14 +28,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces public void Convert_xyY_to_XYZ(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) { var input = new CieXyy(x, y, yl); + var expected = new CieXyz(xyzX, xyzY, xyzZ); // Act - CieXyz output = Converter.ToCieXyz(input); + var actual = Converter.ToCieXyz(input); // Assert - Assert.Equal(xyzX, output.X, FloatRoundingComparer); - Assert.Equal(xyzY, output.Y, FloatRoundingComparer); - Assert.Equal(xyzZ, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } [Theory] @@ -47,14 +45,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces public void Convert_XYZ_to_xyY(float xyzX, float xyzY, float xyzZ, float x, float y, float yl) { var input = new CieXyz(xyzX, xyzY, xyzZ); + var expected = new CieXyy(x, y, yl); // Act - CieXyy output = Converter.ToCieXyy(input); + var actual = Converter.ToCieXyy(input); // Assert - Assert.Equal(x, output.X, FloatRoundingComparer); - Assert.Equal(y, output.Y, FloatRoundingComparer); - Assert.Equal(yl, output.Yl, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs index bea392c167..91ee9f1319 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -9,7 +8,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Colorspaces { /// - /// Tests - conversions. + /// Tests - conversions. /// /// /// Test data generated using: @@ -17,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class CieXyzAndHunterLabConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); /// /// Tests conversion from to (). @@ -30,14 +29,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new HunterLab(l, a, b); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.C }; + var expected = new CieXyz(x, y, z); // Act - CieXyz output = converter.ToCieXyz(input); + var actual = converter.ToCieXyz(input); // Assert - Assert.Equal(x, output.X, FloatRoundingComparer); - Assert.Equal(y, output.Y, FloatRoundingComparer); - Assert.Equal(z, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } /// @@ -51,14 +49,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new HunterLab(l, a, b); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 }; + var expected = new CieXyz(x, y, z); // Act - CieXyz output = converter.ToCieXyz(input); + var actual = converter.ToCieXyz(input); // Assert - Assert.Equal(x, output.X, FloatRoundingComparer); - Assert.Equal(y, output.Y, FloatRoundingComparer); - Assert.Equal(z, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } /// @@ -72,14 +69,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new CieXyz(x, y, z); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 }; + var expected = new HunterLab(l, a, b); // Act - HunterLab output = converter.ToHunterLab(input); + var actual = converter.ToHunterLab(input); // Assert - Assert.Equal(l, output.L, FloatRoundingComparer); - Assert.Equal(a, output.A, FloatRoundingComparer); - Assert.Equal(b, output.B, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs index 45ca9049ab..f7f3414676 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs @@ -9,14 +9,14 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Colorspaces { /// - /// Tests - conversions. + /// Tests - conversions. /// /// /// Test data generated using original colorful library. /// public class CieXyzAndLmsConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(5); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); /// /// Tests conversion from () to . @@ -33,14 +33,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new Lms(l, m, s); var converter = new ColorSpaceConverter(); + var expected = new CieXyz(x, y, z); // Act - CieXyz output = converter.ToCieXyz(input); + var actual = converter.ToCieXyz(input); // Assert - Assert.Equal(x, output.X, FloatRoundingComparer); - Assert.Equal(y, output.Y, FloatRoundingComparer); - Assert.Equal(z, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } /// @@ -58,14 +57,13 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new CieXyz(x, y, z); var converter = new ColorSpaceConverter(); + var expected = new Lms(l, m, s); // Act - Lms output = converter.ToLms(input); + var actual = converter.ToLms(input); // Assert - Assert.Equal(l, output.L, FloatRoundingComparer); - Assert.Equal(m, output.M, FloatRoundingComparer); - Assert.Equal(s, output.S, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs index 1cb3f56c7c..d4d1956f50 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; @@ -17,9 +16,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class ColorConverterAdaptTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(3); - - private static readonly ApproximateFloatComparer ApproximateComparer = new ApproximateFloatComparer(0.0001F); + private static readonly ApproximateFloatComparer ApproximateComparer = new ApproximateFloatComparer(.0001F); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); [Theory] [InlineData(0, 0, 0, 0, 0, 0)] @@ -29,17 +27,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new Rgb(r1, g1, b1, RgbWorkingSpaces.WideGamutRgb); - var expectedOutput = new Rgb(r2, g2, b2, RgbWorkingSpaces.SRgb); + var expected = new Rgb(r2, g2, b2, RgbWorkingSpaces.SRgb); var converter = new ColorSpaceConverter { TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; // Action - Rgb output = converter.Adapt(input); + Rgb actual = converter.Adapt(input); // Assert - Assert.Equal(expectedOutput.WorkingSpace, output.WorkingSpace, ApproximateComparer); - Assert.Equal(expectedOutput.R, output.R, FloatRoundingComparer); - Assert.Equal(expectedOutput.G, output.G, FloatRoundingComparer); - Assert.Equal(expectedOutput.B, output.B, FloatRoundingComparer); + Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ApproximateComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } [Theory] @@ -50,17 +46,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new Rgb(r1, g1, b1, RgbWorkingSpaces.SRgb); - var expectedOutput = new Rgb(r2, g2, b2, RgbWorkingSpaces.WideGamutRgb); + var expected = new Rgb(r2, g2, b2, RgbWorkingSpaces.WideGamutRgb); var converter = new ColorSpaceConverter { TargetRgbWorkingSpace = RgbWorkingSpaces.WideGamutRgb }; // Action - Rgb output = converter.Adapt(input); + Rgb actual = converter.Adapt(input); // Assert - Assert.Equal(expectedOutput.WorkingSpace, output.WorkingSpace, ApproximateComparer); - Assert.Equal(expectedOutput.R, output.R, FloatRoundingComparer); - Assert.Equal(expectedOutput.G, output.G, FloatRoundingComparer); - Assert.Equal(expectedOutput.B, output.B, FloatRoundingComparer); + Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ApproximateComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } [Theory] @@ -70,16 +64,14 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new CieLab(l1, a1, b1, Illuminants.D65); - var expectedOutput = new CieLab(l2, a2, b2); + var expected = new CieLab(l2, a2, b2); var converter = new ColorSpaceConverter { TargetLabWhitePoint = Illuminants.D50 }; // Action - CieLab output = converter.Adapt(input); + CieLab actual = converter.Adapt(input); // Assert - Assert.Equal(expectedOutput.L, output.L, FloatRoundingComparer); - Assert.Equal(expectedOutput.A, output.A, FloatRoundingComparer); - Assert.Equal(expectedOutput.B, output.B, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } [Theory] @@ -88,20 +80,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces public void Adapt_Xyz_D65_To_D50_Bradford(float x1, float y1, float z1, float x2, float y2, float z2) { // Arrange - CieXyz input = new CieXyz(x1, y1, z1); - CieXyz expectedOutput = new CieXyz(x2, y2, z2); - ColorSpaceConverter converter = new ColorSpaceConverter - { - WhitePoint = Illuminants.D50 - }; + var input = new CieXyz(x1, y1, z1); + var expected = new CieXyz(x2, y2, z2); + var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D50 }; // Action - CieXyz output = converter.Adapt(input, Illuminants.D65); + CieXyz actual = converter.Adapt(input, Illuminants.D65); // Assert - Assert.Equal(expectedOutput.X, output.X, FloatRoundingComparer); - Assert.Equal(expectedOutput.Y, output.Y, FloatRoundingComparer); - Assert.Equal(expectedOutput.Z, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } [Theory] @@ -111,7 +98,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new CieXyz(x1, y1, z1); - var expectedOutput = new CieXyz(x2, y2, z2); + var expected = new CieXyz(x2, y2, z2); var converter = new ColorSpaceConverter { ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), @@ -119,12 +106,10 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces }; // Action - CieXyz output = converter.Adapt(input, Illuminants.D65); + CieXyz actual = converter.Adapt(input, Illuminants.D65); // Assert - Assert.Equal(expectedOutput.X, output.X, FloatRoundingComparer); - Assert.Equal(expectedOutput.Y, output.Y, FloatRoundingComparer); - Assert.Equal(expectedOutput.Z, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } [Theory] @@ -134,7 +119,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new CieXyz(x1, y1, z1); - var expectedOutput = new CieXyz(x2, y2, z2); + var expected = new CieXyz(x2, y2, z2); var converter = new ColorSpaceConverter { ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), @@ -142,12 +127,10 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces }; // Action - CieXyz output = converter.Adapt(input, Illuminants.D65); + CieXyz actual = converter.Adapt(input, Illuminants.D65); // Assert - Assert.Equal(expectedOutput.X, output.X, FloatRoundingComparer); - Assert.Equal(expectedOutput.Y, output.Y, FloatRoundingComparer); - Assert.Equal(expectedOutput.Z, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs index b895ee9a46..466c1dca1b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs @@ -17,297 +17,158 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class ColorSpaceEqualityTests { - //internal static readonly Dictionary EmptyDataLookup = - // new Dictionary - // { - // {nameof( CieLab), default(CieLab) }, - // {nameof( CieLch), default(CieLch) }, - // {nameof( CieLchuv), default(CieLchuv) }, - // {nameof( CieLuv), default(CieLuv) }, - // {nameof( CieXyz), default(CieXyz) }, - // {nameof( CieXyy), default(CieXyy) }, - // {nameof( Hsl), default(Hsl) }, - // {nameof( HunterLab), default(HunterLab) }, - // {nameof( Lms), default(Lms) }, - // {nameof( LinearRgb), default(LinearRgb) }, - // {nameof( Rgb), default(Rgb) }, - // {nameof( YCbCr), default(YCbCr) } - // }; - - //public static readonly IEnumerable EmptyData = EmptyDataLookup.Select(x => new[] { x.Key }); - - //public static readonly TheoryData EqualityData = - // new TheoryData - // { - // { new CieLab(Vector3.One), new CieLab(Vector3.One), typeof(CieLab) }, - // { new CieLch(Vector3.One), new CieLch(Vector3.One), typeof(CieLch) }, - // { new CieLchuv(Vector3.One), new CieLchuv(Vector3.One), typeof(CieLchuv) }, - // { new CieLuv(Vector3.One), new CieLuv(Vector3.One), typeof(CieLuv) }, - // { new CieXyz(Vector3.One), new CieXyz(Vector3.One), typeof(CieXyz) }, - // { new CieXyy(Vector3.One), new CieXyy(Vector3.One), typeof(CieXyy) }, - // { new HunterLab(Vector3.One), new HunterLab(Vector3.One), typeof(HunterLab) }, - // { new Lms(Vector3.One), new Lms(Vector3.One), typeof(Lms) }, - // { new LinearRgb(Vector3.One), new LinearRgb(Vector3.One), typeof(LinearRgb) }, - // { new Rgb(Vector3.One), new Rgb(Vector3.One), typeof(Rgb) }, - // { new Hsl(Vector3.One), new Hsl(Vector3.One), typeof(Hsl) }, - // { new Hsv(Vector3.One), new Hsv(Vector3.One), typeof(Hsv) }, - // { new YCbCr(Vector3.One), new YCbCr(Vector3.One), typeof(YCbCr) }, - // }; - - //public static readonly TheoryData NotEqualityDataNulls = - // new TheoryData - // { - // // Valid object against null - // { new CieLab(Vector3.One), null, typeof(CieLab) }, - // { new CieLch(Vector3.One), null, typeof(CieLch) }, - // { new CieLchuv(Vector3.One), null, typeof(CieLchuv) }, - // { new CieLuv(Vector3.One), null, typeof(CieLuv) }, - // { new CieXyz(Vector3.One), null, typeof(CieXyz) }, - // { new CieXyy(Vector3.One), null, typeof(CieXyy) }, - // { new HunterLab(Vector3.One), null, typeof(HunterLab) }, - // { new Lms(Vector3.One), null, typeof(Lms) }, - // { new LinearRgb(Vector3.One), null, typeof(LinearRgb) }, - // { new Rgb(Vector3.One), null, typeof(Rgb) }, - // { new Hsl(Vector3.One), null, typeof(Hsl) }, - // { new Hsv(Vector3.One), null, typeof(Hsv) }, - // { new YCbCr(Vector3.One), null, typeof(YCbCr) }, - // }; - - //public static readonly TheoryData NotEqualityDataDifferentObjects = - // new TheoryData - // { - // // Valid objects of different types but not equal - // { new CieLab(Vector3.One), new CieLch(Vector3.Zero), null }, - // { new CieLuv(Vector3.One), new CieLchuv(Vector3.Zero), null }, - // { new CieXyz(Vector3.One), new HunterLab(Vector3.Zero), null }, - // { new Rgb(Vector3.One), new LinearRgb(Vector3.Zero), null }, - // { new Rgb(Vector3.One), new Lms(Vector3.Zero), null }, - // { new Cmyk(Vector4.One), new Hsl(Vector3.Zero), null }, - // { new YCbCr(Vector3.One), new CieXyy(Vector3.Zero), null }, - // { new Hsv(Vector3.One), new Hsl(Vector3.Zero), null }, - // }; - - //public static readonly TheoryData NotEqualityData = - // new TheoryData - // { - // // Valid objects of the same type but not equal - // { new CieLab(Vector3.One), new CieLab(Vector3.Zero), typeof(CieLab) }, - // { new CieLch(Vector3.One), new CieLch(Vector3.Zero), typeof(CieLch) }, - // { new CieLchuv(Vector3.One), new CieLchuv(Vector3.Zero), typeof(CieLchuv) }, - // { new CieLuv(Vector3.One), new CieLuv(Vector3.Zero), typeof(CieLuv) }, - // { new CieXyz(Vector3.One), new CieXyz(Vector3.Zero), typeof(CieXyz) }, - // { new CieXyy(Vector3.One), new CieXyy(Vector3.Zero), typeof(CieXyy) }, - // { new HunterLab(Vector3.One), new HunterLab(Vector3.Zero), typeof(HunterLab) }, - // { new Lms(Vector3.One), new Lms(Vector3.Zero), typeof(Lms) }, - // { new LinearRgb(Vector3.One), new LinearRgb(Vector3.Zero), typeof(LinearRgb) }, - // { new Rgb(Vector3.One), new Rgb(Vector3.Zero), typeof(Rgb) }, - // { new Cmyk(Vector4.One), new Cmyk(Vector4.Zero), typeof(Cmyk) }, - // { new Hsl(Vector3.One), new Hsl(Vector3.Zero), typeof(Hsl) }, - // { new Hsv(Vector3.One), new Hsv(Vector3.Zero), typeof(Hsv) }, - // { new YCbCr(Vector3.One), new YCbCr(Vector3.Zero), typeof(YCbCr) }, - // }; - - //public static readonly TheoryData AlmostEqualsData = - // new TheoryData - // { - // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), 0F }, - // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), .001F }, - // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), .0001F }, - // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0F), typeof(CieLab), .0005F }, - // { new CieLab(0F, 0F, 0F), new CieLab(0F, .001F, 0F), typeof(CieLab), .001F }, - // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, .0001F), typeof(CieLab), .0001F }, - // { new CieLab(0F, 0F, 0F), new CieLab(.0005F, 0F, 0F), typeof(CieLab), .0005F }, - // { new CieLch(0F, 0F, 0F), new CieLch(0F, .001F, 0F), typeof(CieLch), .001F }, - // { new CieLchuv(0F, 0F, 0F), new CieLchuv(0F, .001F, 0F), typeof(CieLchuv), .001F }, - // { new CieLuv(0F, 0F, 0F), new CieLuv(0F, .001F, 0F), typeof(CieLuv), .001F }, - // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380F), typeof(CieXyz), 0F }, - // { new CieXyz(380F, 380F, 380F), new CieXyz(380.001F, 380F, 380F), typeof(CieXyz), .01F }, - // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380.001F, 380F), typeof(CieXyz), .01F }, - // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380.001F), typeof(CieXyz), .01F }, - // { new Cmyk(1, 1, 1, 1), new Cmyk(1, 1, 1, .99F), typeof(Cmyk), .01F }, - // { new YCbCr(255F, 128F, 128F), new YCbCr(255F, 128F, 128.001F), typeof(YCbCr), .01F }, - // { new Hsv(0F, 0F, 0F), new Hsv(0F, 0F, 0F), typeof(Hsv), 0F }, - // { new Hsl(0F, 0F, 0F), new Hsl(0F, 0F, 0F), typeof(Hsl), 0F }, - // }; - - //public static readonly TheoryData AlmostNotEqualsData = - // new TheoryData - // { - // { new CieLab(0F, 0F, 0F), new CieLab(0.1F, 0F, 0F), typeof(CieLab), .001F }, - // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0.1F, 0F), typeof(CieLab), .001F }, - // { new CieLab(0F, 0F, 0F), new CieLab(0F, 0F, 0.1F), typeof(CieLab), .001F }, - // { new CieXyz(380F, 380F, 380F), new CieXyz(380.1F, 380F, 380F), typeof(CieXyz), .001F }, - // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380.1F, 380F), typeof(CieXyz), .001F }, - // { new CieXyz(380F, 380F, 380F), new CieXyz(380F, 380F, 380.1F), typeof(CieXyz), .001F }, - // }; - - //[Theory] - //[MemberData(nameof(EmptyData))] - //public void Vector_Equals_WhenTrue(string color) - //{ - // IColorVector colorVector = EmptyDataLookup[color]; - // // Act - // bool equal = colorVector.Vector.Equals(Vector3.Zero); - - // // Assert - // Assert.True(equal); - //} - - //[Theory] - //[MemberData(nameof(EqualityData))] - //public void Equals_WhenTrue(object first, object second, Type type) - //{ - // // Act - // bool equal = first.Equals(second); - - // // Assert - // Assert.True(equal); - //} - - //[Theory] - //[MemberData(nameof(NotEqualityDataNulls))] - //[MemberData(nameof(NotEqualityDataDifferentObjects))] - //[MemberData(nameof(NotEqualityData))] - //public void Equals_WhenFalse(object first, object second, Type type) - //{ - // // Act - // bool equal = first.Equals(second); - - // // Assert - // Assert.False(equal); - //} - - //[Theory] - //[MemberData(nameof(EqualityData))] - //public void GetHashCode_WhenEqual(object first, object second, Type type) - //{ - // // Act - // bool equal = first.GetHashCode() == second.GetHashCode(); - - // // Assert - // Assert.True(equal); - //} - - //[Theory] - //[MemberData(nameof(NotEqualityDataDifferentObjects))] - //public void GetHashCode_WhenNotEqual(object first, object second, Type type) - //{ - // // Act - // bool equal = first.GetHashCode() == second.GetHashCode(); - - // // Assert - // Assert.False(equal); - //} - - //[Theory] - //[MemberData(nameof(EqualityData))] - //public void GenericEquals_WhenTrue(object first, object second, Type type) - //{ - // // Arrange - // // Cast to the known object types, this is so that we can hit the - // // equality operator on the concrete type, otherwise it goes to the - // // default "object" one :) - // dynamic firstObject = Convert.ChangeType(first, type); - // dynamic secondObject = Convert.ChangeType(second, type); - - // // Act - // dynamic equal = firstObject.Equals(secondObject); - - // // Assert - // Assert.True(equal); - //} - - //[Theory] - //[MemberData(nameof(NotEqualityData))] - //public void GenericEquals_WhenFalse(object first, object second, Type type) - //{ - // // Arrange - // // Cast to the known object types, this is so that we can hit the - // // equality operator on the concrete type, otherwise it goes to the - // // default "object" one :) - // dynamic firstObject = Convert.ChangeType(first, type); - // dynamic secondObject = Convert.ChangeType(second, type); - - // // Act - // dynamic equal = firstObject.Equals(secondObject); - - // // Assert - // Assert.False(equal); - //} - - //// TODO:Disabled due to RuntypeBinder errors while structs are internal - ////[Theory] - ////[MemberData(nameof(EqualityData))] - ////public void EqualityOperator(object first, object second, Type type) - ////{ - //// // Arrange - //// // Cast to the known object types, this is so that we can hit the - //// // equality operator on the concrete type, otherwise it goes to the - //// // default "object" one :) - //// dynamic firstObject = Convert.ChangeType(first, type); - //// dynamic secondObject = Convert.ChangeType(second, type); - - //// // Act - //// dynamic equal = firstObject == secondObject; - - //// // Assert - //// Assert.True(equal); - ////} - - //[Theory] - //[MemberData(nameof(NotEqualityData))] - //public void Operator_WhenTrue(object first, object second, Type type) - //{ - // // Arrange - // // Cast to the known object types, this is so that we can hit the - // // equality operator on the concrete type, otherwise it goes to the - // // default "object" one :) - // dynamic firstObject = Convert.ChangeType(first, type); - // dynamic secondObject = Convert.ChangeType(second, type); - - // // Act - // dynamic notEqual = firstObject != secondObject; - - // // Assert - // Assert.True(notEqual); - //} - - //// TODO:Disabled due to RuntypeBinder errors while structs are internal - ////[Theory] - ////[MemberData(nameof(AlmostEqualsData))] - ////public void AlmostEquals(object first, object second, Type type, float precision) - ////{ - //// // Arrange - //// // Cast to the known object types, this is so that we can hit the - //// // equality operator on the concrete type, otherwise it goes to the - //// // default "object" one :) - //// dynamic firstObject = Convert.ChangeType(first, type); - //// dynamic secondObject = Convert.ChangeType(second, type); - - //// // Act - //// dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision); - - //// // Assert - //// Assert.True(almostEqual); - ////} - - //// TODO:Disabled due to RuntypeBinder errors while structs are internal - ////[Theory] - ////[MemberData(nameof(AlmostNotEqualsData))] - ////public void AlmostNotEquals(object first, object second, Type type, float precision) - ////{ - //// // Arrange - //// // Cast to the known object types, this is so that we can hit the - //// // equality operator on the concrete type, otherwise it goes to the - //// // default "object" one :) - //// dynamic firstObject = Convert.ChangeType(first, type); - //// dynamic secondObject = Convert.ChangeType(second, type); - - //// // Act - //// dynamic almostEqual = firstObject.AlmostEquals(secondObject, precision); - - //// // Assert - //// Assert.False(almostEqual); - ////} + [Fact] + public void CieLabEquality() + { + var x = default(CieLab); + var y = new CieLab(Vector3.One); + Assert.Equal(default(CieLab), default(CieLab)); + Assert.Equal(new CieLab(1, 0, 1), new CieLab(1, 0, 1)); + Assert.Equal(new CieLab(Vector3.One), new CieLab(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void CieLchEquality() + { + var x = default(CieLch); + var y = new CieLch(Vector3.One); + Assert.Equal(default(CieLch), default(CieLch)); + Assert.Equal(new CieLch(1, 0, 1), new CieLch(1, 0, 1)); + Assert.Equal(new CieLch(Vector3.One), new CieLch(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void CieLchuvEquality() + { + var x = default(CieLchuv); + var y = new CieLchuv(Vector3.One); + Assert.Equal(default(CieLchuv), default(CieLchuv)); + Assert.Equal(new CieLchuv(1, 0, 1), new CieLchuv(1, 0, 1)); + Assert.Equal(new CieLchuv(Vector3.One), new CieLchuv(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void CieLuvEquality() + { + var x = default(CieLuv); + var y = new CieLuv(Vector3.One); + Assert.Equal(default(CieLuv), default(CieLuv)); + Assert.Equal(new CieLuv(1, 0, 1), new CieLuv(1, 0, 1)); + Assert.Equal(new CieLuv(Vector3.One), new CieLuv(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void CieXyzEquality() + { + var x = default(CieXyz); + var y = new CieXyz(Vector3.One); + Assert.Equal(default(CieXyz), default(CieXyz)); + Assert.Equal(new CieXyz(1, 0, 1), new CieXyz(1, 0, 1)); + Assert.Equal(new CieXyz(Vector3.One), new CieXyz(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void CieXyyEquality() + { + var x = default(CieXyy); + var y = new CieXyy(Vector3.One); + Assert.Equal(default(CieXyy), default(CieXyy)); + Assert.Equal(new CieXyy(1, 0, 1), new CieXyy(1, 0, 1)); + Assert.Equal(new CieXyy(Vector3.One), new CieXyy(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void HslEquality() + { + var x = default(Hsl); + var y = new Hsl(Vector3.One); + Assert.Equal(default(Hsl), default(Hsl)); + Assert.Equal(new Hsl(1, 0, 1), new Hsl(1, 0, 1)); + Assert.Equal(new Hsl(Vector3.One), new Hsl(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void HsvEquality() + { + var x = default(Hsv); + var y = new Hsv(Vector3.One); + Assert.Equal(default(Hsv), default(Hsv)); + Assert.Equal(new Hsv(1, 0, 1), new Hsv(1, 0, 1)); + Assert.Equal(new Hsv(Vector3.One), new Hsv(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void HunterLabEquality() + { + var x = default(HunterLab); + var y = new HunterLab(Vector3.One); + Assert.Equal(default(HunterLab), default(HunterLab)); + Assert.Equal(new HunterLab(1, 0, 1), new HunterLab(1, 0, 1)); + Assert.Equal(new HunterLab(Vector3.One), new HunterLab(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void LmsEquality() + { + var x = default(Lms); + var y = new Lms(Vector3.One); + Assert.Equal(default(Lms), default(Lms)); + Assert.Equal(new Lms(1, 0, 1), new Lms(1, 0, 1)); + Assert.Equal(new Lms(Vector3.One), new Lms(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void LinearRgbEquality() + { + var x = default(LinearRgb); + var y = new LinearRgb(Vector3.One); + Assert.Equal(default(LinearRgb), default(LinearRgb)); + Assert.Equal(new LinearRgb(1, 0, 1), new LinearRgb(1, 0, 1)); + Assert.Equal(new LinearRgb(Vector3.One), new LinearRgb(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void RgbEquality() + { + var x = default(Rgb); + var y = new Rgb(Vector3.One); + Assert.Equal(default(Rgb), default(Rgb)); + Assert.Equal(new Rgb(1, 0, 1), new Rgb(1, 0, 1)); + Assert.Equal(new Rgb(Vector3.One), new Rgb(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void YCbCrEquality() + { + var x = default(YCbCr); + var y = new YCbCr(Vector3.One); + Assert.Equal(default(YCbCr), default(YCbCr)); + Assert.Equal(new YCbCr(1, 0, 1), new YCbCr(1, 0, 1)); + Assert.Equal(new YCbCr(Vector3.One), new YCbCr(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void CmykEquality() + { + var x = default(Cmyk); + var y = new Cmyk(Vector4.One); + Assert.Equal(default(Cmyk), default(Cmyk)); + Assert.Equal(new Cmyk(1, 0, 1, 0), new Cmyk(1, 0, 1, 0)); + Assert.Equal(new Cmyk(Vector4.One), new Cmyk(Vector4.One)); + Assert.False(x.Equals(y)); + } } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 8fa796c12b..7c2eb82383 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg seed); } - private static void ValidateYCbCr(JpegColorConverter.ComponentValues values, Vector4[] result, int i) + private static void ValidateYCbCr(in JpegColorConverter.ComponentValues values, Vector4[] result, int i) { float y = values.Component0[i]; float cb = values.Component1[i]; From 53798df51c2af84cc4e8c8dae523ec1f5fffb75c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 27 Jul 2018 15:04:32 +0100 Subject: [PATCH 020/185] Bulk colorspace conversion tests --- .../Implementation/RgbWorkingSpace.cs | 33 ++---- .../ApproximateColorspaceComparer.cs | 112 +++++++++++++++++- .../CieLabAndCieLchConversionTests.cs | 23 ++++ .../CieLuvAndCieLchuvConversionTests.cs | 24 ++++ .../CieXyzAndCieLabConversionTest.cs | 23 ++++ .../CieXyzAndCieLuvConversionTest.cs | 23 ++++ .../CieXyzAndCieXyyConversionTest.cs | 24 +++- .../CieXyzAndHunterLabConversionTest.cs | 34 ++++++ .../Colorspaces/CieXyzAndLmsConversionTest.cs | 13 +- .../Colorspaces/ColorConverterAdaptTest.cs | 5 +- .../Colorspaces/RgbAndCieXyzConversionTest.cs | 87 ++++++++++---- .../Colorspaces/RgbAndCmykConversionTest.cs | 46 ++++--- .../Colorspaces/RgbAndHslConversionTest.cs | 46 ++++--- .../Colorspaces/RgbAndHsvConversionTest.cs | 45 ++++--- .../Colorspaces/RgbAndYCbCrConversionTest.cs | 45 ++++--- .../TestUtilities/ApproximateFloatComparer.cs | 76 +++--------- .../TestUtilities/FloatRoundingComparer.cs | 68 ----------- 17 files changed, 488 insertions(+), 239 deletions(-) delete mode 100644 tests/ImageSharp.Tests/TestUtilities/FloatRoundingComparer.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs index 2d3bae4028..101d135f57 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; + namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Trivial implementation of /// - internal class RgbWorkingSpace + internal class RgbWorkingSpace : IEquatable { /// /// Initializes a new instance of the class. @@ -39,12 +41,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is equal to the parameter; otherwise, false. /// @@ -56,12 +54,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Compares two objects for inequality /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the current left is unequal to the parameter; otherwise, false. /// @@ -70,11 +64,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return !Equals(left, right); } + /// public override bool Equals(object obj) { return obj is RgbWorkingSpace other && this.Equals(other); } + /// public bool Equals(RgbWorkingSpace other) { // TODO: Object.Equals for ICompanding will be slow. @@ -86,13 +82,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public override int GetHashCode() { - unchecked - { - int hashCode = this.WhitePoint.GetHashCode(); - hashCode = (hashCode * 397) ^ this.ChromaticityCoordinates.GetHashCode(); - hashCode = (hashCode * 397) ^ (this.Companding?.GetHashCode() ?? 0); - return hashCode; - } + int hash = this.WhitePoint.GetHashCode(); + hash = HashHelpers.Combine(hash, this.ChromaticityCoordinates.GetHashCode()); + hash = HashHelpers.Combine(hash, this.Companding?.GetHashCode() ?? 0); + return hash; } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs index faba575de0..88aa572ee5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs @@ -3,13 +3,14 @@ using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.Tests.Colorspaces { /// /// Allows the approximate comparison of colorspace component values. /// - internal class ApproximateColorSpaceComparer : + internal readonly struct ApproximateColorSpaceComparer : IEqualityComparer, IEqualityComparer, IEqualityComparer, @@ -17,8 +18,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces IEqualityComparer, IEqualityComparer, IEqualityComparer, + IEqualityComparer, IEqualityComparer, - IEqualityComparer + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer, + IEqualityComparer { private readonly float Epsilon; @@ -129,6 +137,21 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces return obj.GetHashCode(); } + /// + public bool Equals(Cmyk x, Cmyk y) + { + return this.Equals(x.C, y.C) + && this.Equals(x.M, y.M) + && this.Equals(x.Y, y.Y) + && this.Equals(x.K, y.K); + } + + /// + public int GetHashCode(Cmyk obj) + { + return obj.GetHashCode(); + } + /// public bool Equals(HunterLab x, HunterLab y) { @@ -143,6 +166,34 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces return obj.GetHashCode(); } + /// + public bool Equals(Hsl x, Hsl y) + { + return this.Equals(x.H, y.H) + && this.Equals(x.S, y.S) + && this.Equals(x.L, y.L); + } + + /// + public int GetHashCode(Hsl obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(Hsv x, Hsv y) + { + return this.Equals(x.H, y.H) + && this.Equals(x.S, y.S) + && this.Equals(x.V, y.V); + } + + /// + public int GetHashCode(Hsv obj) + { + return obj.GetHashCode(); + } + /// public bool Equals(Lms x, Lms y) { @@ -157,6 +208,63 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces return obj.GetHashCode(); } + /// + public bool Equals(YCbCr x, YCbCr y) + { + return this.Equals(x.Y, y.Y) + && this.Equals(x.Cb, y.Cb) + && this.Equals(x.Cr, y.Cr); + } + + /// + public int GetHashCode(YCbCr obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(CieXyChromaticityCoordinates x, CieXyChromaticityCoordinates y) + { + return this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y); + } + + /// + public int GetHashCode(CieXyChromaticityCoordinates obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(RgbPrimariesChromaticityCoordinates x, RgbPrimariesChromaticityCoordinates y) + { + return this.Equals(x.R, y.R) && this.Equals(x.G, y.G) && this.Equals(x.B, y.B); + } + + /// + public int GetHashCode(RgbPrimariesChromaticityCoordinates obj) + { + return obj.GetHashCode(); + } + + /// + public bool Equals(RgbWorkingSpace x, RgbWorkingSpace y) + { + if (x is RgbWorkingSpace g1 && y is RgbWorkingSpace g2) + { + return this.Equals(g1.WhitePoint, g2.WhitePoint) + && this.Equals(g1.ChromaticityCoordinates, g2.ChromaticityCoordinates); + } + + return this.Equals(x.WhitePoint, y.WhitePoint) + && this.Equals(x.ChromaticityCoordinates, y.ChromaticityCoordinates); + } + + /// + public int GetHashCode(RgbWorkingSpace obj) + { + return obj.GetHashCode(); + } + private bool Equals(float x, float y) { float d = x - y; diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs index 0425d8e209..de63a3dbf0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -37,11 +38,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var input = new CieLch(l, c, h); var expected = new CieLab(l2, a, b); + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + // Act var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -62,11 +74,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var input = new CieLab(l, a, b); var expected = new CieLch(l2, c, h); + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + // Act var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs index 1bff994e1d..cb83340877 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -37,11 +38,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var input = new CieLchuv(l, c, h); var expected = new CieLuv(l2, u, v); + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + // Act var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -63,11 +75,23 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var input = new CieLuv(l, u, v); var expected = new CieLchuv(l2, c, h); + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + // Act var actual = Converter.ToCieLchuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs index bf582650bc..763c607700 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -37,11 +38,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; var expected = new CieXyz(x, y, z); + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + // Act var actual = converter.ToCieXyz(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -61,11 +73,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; var expected = new CieLab(l, a, b); + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + // Act var actual = converter.ToCieLab(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs index 66150fe040..df80db2d29 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -36,11 +37,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; var expected = new CieXyz(x, y, z); + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + // Act var actual = converter.ToCieXyz(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -60,11 +72,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; var expected = new CieLuv(l, u, v); + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + // Act var actual = converter.ToCieLuv(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs index 46bdf80709..2686a8228f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -30,11 +30,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var input = new CieXyy(x, y, yl); var expected = new CieXyz(xyzX, xyzY, xyzZ); + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + // Act var actual = Converter.ToCieXyz(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } [Theory] @@ -47,11 +58,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var input = new CieXyz(xyzX, xyzY, xyzZ); var expected = new CieXyy(x, y, yl); + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + // Act var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs index 91ee9f1319..6e547e9e42 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -31,11 +32,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var converter = new ColorSpaceConverter { WhitePoint = Illuminants.C }; var expected = new CieXyz(x, y, z); + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + // Act var actual = converter.ToCieXyz(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -51,11 +63,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 }; var expected = new CieXyz(x, y, z); + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + // Act var actual = converter.ToCieXyz(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -71,11 +94,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 }; var expected = new HunterLab(l, a, b); + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + // Act var actual = converter.ToHunterLab(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs index f7f3414676..eb7e8fa86d 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -35,11 +35,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces var converter = new ColorSpaceConverter(); var expected = new CieXyz(x, y, z); + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + // Act var actual = converter.ToCieXyz(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs index d4d1956f50..aa7325a51a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs @@ -16,7 +16,6 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class ColorConverterAdaptTest { - private static readonly ApproximateFloatComparer ApproximateComparer = new ApproximateFloatComparer(.0001F); private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); [Theory] @@ -34,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces Rgb actual = converter.Adapt(input); // Assert - Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ApproximateComparer); + Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ColorSpaceComparer); Assert.Equal(expected, actual, ColorSpaceComparer); } @@ -53,7 +52,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces Rgb actual = converter.Adapt(input); // Assert - Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ApproximateComparer); + Assert.Equal(expected.WorkingSpace, actual.WorkingSpace, ColorSpaceComparer); Assert.Equal(expected, actual, ColorSpaceComparer); } diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs index 929c35ee90..92ab75a8a6 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -17,9 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class RgbAndCieXyzConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(5); - - private static readonly ApproximateFloatComparer ApproximateComparer = new ApproximateFloatComparer(0.0001F); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); /// /// Tests conversion from () @@ -37,17 +35,25 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new CieXyz(x, y, z); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D50, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + var expected = new Rgb(r, g, b); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; // Act - Rgb output = converter.ToRgb(input); + var actual = converter.ToRgb(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - IEqualityComparer comparer = new ApproximateFloatComparer(0.001f); + Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); - Assert.Equal(Rgb.DefaultWorkingSpace, output.WorkingSpace, ApproximateComparer); - Assert.Equal(r, output.R, comparer); - Assert.Equal(g, output.G, comparer); - Assert.Equal(b, output.B, comparer); + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -65,17 +71,27 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces public void Convert_XYZ_D65_to_SRGB(float x, float y, float z, float r, float g, float b) { // Arrange - CieXyz input = new CieXyz(x, y, z); - ColorSpaceConverter converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + var input = new CieXyz(x, y, z); + var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + var expected = new Rgb(r, g, b); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; // Act - Rgb output = converter.ToRgb(input); + var actual = converter.ToRgb(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, output.WorkingSpace, ApproximateComparer); - Assert.Equal(r, output.R, FloatRoundingComparer); - Assert.Equal(g, output.G, FloatRoundingComparer); - Assert.Equal(b, output.B, FloatRoundingComparer); + Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -94,15 +110,24 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new Rgb(r, g, b); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D50 }; + var expected = new CieXyz(x, y, z); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; // Act - CieXyz output = converter.ToCieXyz(input); + var actual = converter.ToCieXyz(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - IEqualityComparer comparer = new ApproximateFloatComparer(0.001f); - Assert.Equal(x, output.X, comparer); - Assert.Equal(y, output.Y, comparer); - Assert.Equal(z, output.Z, comparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -121,14 +146,24 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces // Arrange var input = new Rgb(r, g, b); var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 }; + var expected = new CieXyz(x, y, z); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; // Act - CieXyz output = converter.ToCieXyz(input); + var actual = converter.ToCieXyz(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(x, output.X, FloatRoundingComparer); - Assert.Equal(y, output.Y, FloatRoundingComparer); - Assert.Equal(z, output.Z, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs index 495ae20179..a8a9a05674 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -18,11 +18,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class RgbAndCmykConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - private static readonly ApproximateFloatComparer ApproximateComparer = new ApproximateFloatComparer(0.0001F); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); /// /// Tests conversion from to . @@ -35,15 +32,25 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new Cmyk(c, m, y, k); + var expected = new Rgb(r, g, b); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; // Act - var output = Converter.ToRgb(input); + var actual = Converter.ToRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, output.WorkingSpace, ApproximateComparer); - Assert.Equal(r, output.R, FloatRoundingComparer); - Assert.Equal(g, output.G, FloatRoundingComparer); - Assert.Equal(b, output.B, FloatRoundingComparer); + Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -57,15 +64,24 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new Rgb(r, g, b); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; // Act - var output = Converter.ToCmyk(input); + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(c, output.C, FloatRoundingComparer); - Assert.Equal(m, output.M, FloatRoundingComparer); - Assert.Equal(y, output.Y, FloatRoundingComparer); - Assert.Equal(k, output.K, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs index 4f15379329..ba7aab5ea5 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -18,11 +18,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class RgbAndHslConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - private static readonly ApproximateFloatComparer ApproximateComparer = new ApproximateFloatComparer(0.0001F); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); /// /// Tests conversion from to . @@ -38,15 +35,25 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new Hsl(h, s, l); + var expected = new Rgb(r, g, b); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; // Act - Rgb output = Converter.ToRgb(input); + var actual = Converter.ToRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, output.WorkingSpace, ApproximateComparer); - Assert.Equal(r, output.R, FloatRoundingComparer); - Assert.Equal(g, output.G, FloatRoundingComparer); - Assert.Equal(b, output.B, FloatRoundingComparer); + Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -62,14 +69,25 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new Rgb(r, g, b); + var expected = new Hsl(h, s, l); + + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; // Act - Hsl output = Converter.ToHsl(input); + var actual = Converter.ToHsl(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(h, output.H, FloatRoundingComparer); - Assert.Equal(s, output.S, FloatRoundingComparer); - Assert.Equal(l, output.L, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs index 7f46ff1fc9..89829e9d97 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -17,11 +17,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class RgbAndHsvConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(4); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - private static readonly ApproximateFloatComparer ApproximateComparer = new ApproximateFloatComparer(0.0001F); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); /// /// Tests conversion from to . @@ -37,15 +34,25 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new Hsv(h, s, v); + var expected = new Rgb(r, g, b); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; // Act - Rgb output = Converter.ToRgb(input); + var actual = Converter.ToRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, output.WorkingSpace, ApproximateComparer); - Assert.Equal(r, output.R, FloatRoundingComparer); - Assert.Equal(g, output.G, FloatRoundingComparer); - Assert.Equal(b, output.B, FloatRoundingComparer); + Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -61,14 +68,24 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new Rgb(r, g, b); + var expected = new Hsv(h, s, v); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; // Act - Hsv output = Converter.ToHsv(input); + var actual = Converter.ToHsv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(h, output.H, FloatRoundingComparer); - Assert.Equal(s, output.S, FloatRoundingComparer); - Assert.Equal(v, output.V, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs index 46c12e3a55..2e66dd7b02 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Collections.Generic; +using System; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; @@ -16,11 +16,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces /// public class RgbAndYCbCrConversionTest { - private static readonly IEqualityComparer FloatRoundingComparer = new FloatRoundingComparer(3); - private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); - - private static readonly ApproximateFloatComparer ApproximateComparer = new ApproximateFloatComparer(0.0001F); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.001F); /// /// Tests conversion from to . @@ -33,15 +30,25 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new YCbCr(y, cb, cr); + var expected = new Rgb(r, g, b); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; // Act - Rgb output = Converter.ToRgb(input); + var actual = Converter.ToRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(Rgb.DefaultWorkingSpace, output.WorkingSpace, ApproximateComparer); - Assert.Equal(r, output.R, FloatRoundingComparer); - Assert.Equal(g, output.G, FloatRoundingComparer); - Assert.Equal(b, output.B, FloatRoundingComparer); + Assert.Equal(Rgb.DefaultWorkingSpace, actual.WorkingSpace, ColorSpaceComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } /// @@ -56,14 +63,24 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { // Arrange var input = new Rgb(r, g, b); + var expected = new YCbCr(y, cb, cr); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; // Act - YCbCr output = Converter.ToYCbCr(input); + var actual = Converter.ToYCbCr(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert - Assert.Equal(y, output.Y, FloatRoundingComparer); - Assert.Equal(cb, output.Cb, FloatRoundingComparer); - Assert.Equal(cr, output.Cr, FloatRoundingComparer); + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs index 63b8b358de..f0e255c7c6 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -4,36 +4,37 @@ using System; using System.Collections.Generic; using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.Tests { - internal struct ApproximateFloatComparer : + /// + /// Allows the approximate comparison of single precision floating point values. + /// + internal readonly struct ApproximateFloatComparer : IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer, - IEqualityComparer + IEqualityComparer { - private readonly float Eps; + private readonly float Epsilon; - public ApproximateFloatComparer(float eps = 1f) + /// + /// Initializes a new instance of the class. + /// + /// The comparison error difference epsilon to use. + public ApproximateFloatComparer(float epsilon = 1f) { - this.Eps = eps; + this.Epsilon = epsilon; } public bool Equals(float x, float y) { float d = x - y; - return d >= -this.Eps && d <= this.Eps; + return d >= -this.Epsilon && d <= this.Epsilon; } public int GetHashCode(float obj) { - throw new InvalidOperationException(); + return obj.GetHashCode(); } public bool Equals(Vector4 x, Vector4 y) @@ -43,54 +44,7 @@ namespace SixLabors.ImageSharp.Tests public int GetHashCode(Vector4 obj) { - throw new InvalidOperationException(); - } - - public bool Equals(CieXyChromaticityCoordinates x, CieXyChromaticityCoordinates y) - { - return this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y); - } - - public int GetHashCode(CieXyChromaticityCoordinates obj) - { - throw new NotImplementedException(); - } - - public bool Equals(RgbPrimariesChromaticityCoordinates x, RgbPrimariesChromaticityCoordinates y) - { - return this.Equals(x.R, y.R) && this.Equals(x.G, y.G) && this.Equals(x.B, y.B); - } - - public int GetHashCode(RgbPrimariesChromaticityCoordinates obj) - { - throw new NotImplementedException(); - } - - public bool Equals(CieXyz x, CieXyz y) - { - return this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z); - } - - public int GetHashCode(CieXyz obj) - { - throw new NotImplementedException(); - } - - public bool Equals(RgbWorkingSpace x, RgbWorkingSpace y) - { - if (x is RgbWorkingSpace g1 && y is RgbWorkingSpace g2) - { - return this.Equals(g1.WhitePoint, g2.WhitePoint) - && this.Equals(g1.ChromaticityCoordinates, g2.ChromaticityCoordinates); - } - - return this.Equals(x.WhitePoint, y.WhitePoint) - && this.Equals(x.ChromaticityCoordinates, y.ChromaticityCoordinates); - } - - public int GetHashCode(RgbWorkingSpace obj) - { - throw new NotImplementedException(); + return obj.GetHashCode(); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/FloatRoundingComparer.cs b/tests/ImageSharp.Tests/TestUtilities/FloatRoundingComparer.cs deleted file mode 100644 index 27c675823f..0000000000 --- a/tests/ImageSharp.Tests/TestUtilities/FloatRoundingComparer.cs +++ /dev/null @@ -1,68 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Collections.Generic; -using System.Numerics; - -namespace SixLabors.ImageSharp.Tests -{ - /// - /// Allows the comparison of single-precision floating point values by precision. - /// - public struct FloatRoundingComparer : IEqualityComparer, IEqualityComparer - { - /// - /// Initializes a new instance of the struct. - /// - /// The number of decimal places (valid values: 0-7) - public FloatRoundingComparer(int precision) - { - Guard.MustBeBetweenOrEqualTo(precision, 0, 7, nameof(precision)); - this.Precision = precision; - } - - /// - /// Gets the number of decimal places (valid values: 0-7) - /// - public int Precision { get; } - - /// - public bool Equals(float x, float y) - { - float xp = (float)Math.Round(x, this.Precision, MidpointRounding.AwayFromZero); - float yp = (float)Math.Round(y, this.Precision, MidpointRounding.AwayFromZero); - - // ReSharper disable once CompareOfFloatsByEqualityOperator - return xp == yp; - } - - /// - public bool Equals(Vector4 x, Vector4 y) - { - return this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z) && this.Equals(x.W, y.W); - } - - /// - public int GetHashCode(float obj) - { - unchecked - { - int hashCode = obj.GetHashCode(); - hashCode = (hashCode * 397) ^ this.Precision.GetHashCode(); - return hashCode; - } - } - - /// - public int GetHashCode(Vector4 obj) - { - unchecked - { - int hashCode = obj.GetHashCode(); - hashCode = (hashCode * 397) ^ this.Precision.GetHashCode(); - return hashCode; - } - } - } -} \ No newline at end of file From b78c0222944d6230fa58e60d28d4d95bb8eb7429 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 27 Jul 2018 15:55:09 +0100 Subject: [PATCH 021/185] Make colorspaces public --- src/ImageSharp/ColorSpaces/CieLab.cs | 2 +- src/ImageSharp/ColorSpaces/CieLch.cs | 2 +- src/ImageSharp/ColorSpaces/CieLchuv.cs | 2 +- src/ImageSharp/ColorSpaces/CieLuv.cs | 2 +- .../CieXyChromaticityCoordinates.cs | 2 +- src/ImageSharp/ColorSpaces/CieXyy.cs | 2 +- src/ImageSharp/ColorSpaces/CieXyz.cs | 2 +- src/ImageSharp/ColorSpaces/Cmyk.cs | 2 +- .../Conversion/ColorSpaceConverter.Adapt.cs | 2 +- .../Conversion/ColorSpaceConverter.CieLab.cs | 2 +- .../Conversion/ColorSpaceConverter.CieLch.cs | 2 +- .../ColorSpaceConverter.CieLchuv.cs | 2 +- .../Conversion/ColorSpaceConverter.CieLuv.cs | 2 +- .../Conversion/ColorSpaceConverter.CieXyy.cs | 2 +- .../Conversion/ColorSpaceConverter.CieXyz.cs | 2 +- .../Conversion/ColorSpaceConverter.Cmyk.cs | 2 +- .../Conversion/ColorSpaceConverter.Hsl.cs | 2 +- .../Conversion/ColorSpaceConverter.Hsv.cs | 2 +- .../ColorSpaceConverter.HunterLab.cs | 2 +- .../ColorSpaceConverter.LinearRgb.cs | 2 +- .../Conversion/ColorSpaceConverter.Lms.cs | 2 +- .../Conversion/ColorSpaceConverter.Rgb.cs | 2 +- .../Conversion/ColorSpaceConverter.YCbCr.cs | 2 +- .../Conversion/ColorSpaceConverter.cs | 2 +- .../Conversion/IChromaticAdaptation.cs | 2 +- .../Implementation/CIeLchToCieLabConverter.cs | 2 +- .../Implementation/CieLabToCieLchConverter.cs | 2 +- .../Implementation/CieLabToCieXyzConverter.cs | 2 +- .../CieLchuvToCieLuvConverter.cs | 2 +- .../CieLuvToCieLchuvConverter.cs | 2 +- .../Implementation/CieLuvToCieXyzConverter.cs | 2 +- .../CieXyzAndCieXyyConverter.cs | 2 +- .../Implementation/CieXyzAndLmsConverter.cs | 2 +- .../Implementation/CieXyzToCieLabConverter.cs | 2 +- .../Implementation/CieXyzToCieLuvConverter.cs | 2 +- .../CieXyzToHunterLabConverter.cs | 2 +- .../Implementation/CmykAndRgbConverter.cs | 2 +- .../Implementation/GammaCompanding.cs | 2 +- .../Implementation/HslAndRgbConverter.cs | 2 +- .../Implementation/HsvAndRgbConverter.cs | 2 +- .../HunterLabToCieXyzConverter.cs | 2 +- .../Conversion/Implementation/LCompanding.cs | 2 +- .../Implementation/LinearRgbToRgbConverter.cs | 4 +- .../Implementation/LmsAdaptationMatrix.cs | 92 +++++++++++++------ .../RGBPrimariesChromaticityCoordinates.cs | 2 +- .../Implementation/Rec2020Companding.cs | 2 +- .../Implementation/Rec709Companding.cs | 2 +- .../Implementation/RgbWorkingSpace.cs | 2 +- .../Implementation/SRgbCompanding.cs | 2 +- .../Implementation/YCbCrAndRgbConverter.cs | 2 +- .../Conversion/VonKriesChromaticAdaptation.cs | 4 +- src/ImageSharp/ColorSpaces/Hsl.cs | 2 +- src/ImageSharp/ColorSpaces/Hsv.cs | 2 +- src/ImageSharp/ColorSpaces/HunterLab.cs | 2 +- .../ColorSpaces/IAlmostEquatable.cs | 28 ------ src/ImageSharp/ColorSpaces/ICompanding.cs | 2 +- src/ImageSharp/ColorSpaces/Illuminants.cs | 2 +- src/ImageSharp/ColorSpaces/LinearRgb.cs | 2 +- src/ImageSharp/ColorSpaces/Lms.cs | 2 +- src/ImageSharp/ColorSpaces/Rgb.cs | 24 +++-- .../ColorSpaces/RgbWorkingSpaces.cs | 2 +- src/ImageSharp/ColorSpaces/YCbCr.cs | 2 +- src/ImageSharp/PixelFormats/Rgb24.cs | 15 +++ src/ImageSharp/PixelFormats/Rgba32.cs | 15 +++ 64 files changed, 171 insertions(+), 125 deletions(-) delete mode 100644 src/ImageSharp/ColorSpaces/IAlmostEquatable.cs diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 3b2815dd72..305a3da4fb 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents a CIE L*a*b* 1976 color. /// /// - internal readonly struct CieLab : IEquatable + public readonly struct CieLab : IEquatable { /// /// D50 standard illuminant. diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index eea9e24a31..793b68879a 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents the CIE L*C*h°, cylindrical form of the CIE L*a*b* 1976 color. /// /// - internal readonly struct CieLch : IEquatable + public readonly struct CieLch : IEquatable { /// /// D50 standard illuminant. diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index 6538ccbbcf..1a592c93f8 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color. /// /// - internal readonly struct CieLchuv : IEquatable + public readonly struct CieLchuv : IEquatable { /// /// D50 standard illuminant. diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index 970362eaec..f6b2cd1103 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// attempted perceptual uniformity /// /// - internal readonly struct CieLuv : IEquatable + public readonly struct CieLuv : IEquatable { /// /// D65 standard illuminant. diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs index de6725f760..db292041bc 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents the coordinates of CIEXY chromaticity space /// - internal readonly struct CieXyChromaticityCoordinates : IEquatable + public readonly struct CieXyChromaticityCoordinates : IEquatable { /// /// Gets the chromaticity X-coordinate. diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index 976454a31b..9d2fed225d 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents an CIE xyY 1931 color /// /// - internal readonly struct CieXyy : IEquatable + public readonly struct CieXyy : IEquatable { /// /// Gets the X chrominance component. diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index d23be97449..5d4acbcfda 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents an CIE XYZ 1931 color /// /// - internal readonly struct CieXyz : IEquatable + public readonly struct CieXyz : IEquatable { /// /// Gets the X component. A mix (a linear combination) of cone response curves chosen to be nonnegative. diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index 1fa097d9e8..f862151890 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents an CMYK (cyan, magenta, yellow, keyline) color. /// - internal readonly struct Cmyk : IEquatable + public readonly struct Cmyk : IEquatable { /// /// Gets the cyan color component. diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index beccfc351e..055e9fbfc7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Performs chromatic adaptation on the various color spaces. /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { /// /// Performs chromatic adaptation of given color. diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index ebafa961bd..37f0e8567d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { /// /// The converter for converting between CieLch to CieLab. diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 6664cc2274..0f54471e60 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { /// /// The converter for converting between CieLab to CieLch. diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 81f7dcb36b..77e707621a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { /// /// The converter for converting between CieLab to CieLchuv. diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index ba53ad17c7..a0dc4ea890 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { private static readonly CieLchuvToCieLuvConverter CieLchuvToCieLuvConverter = new CieLchuvToCieLuvConverter(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index 464c5ff919..b9958af49c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { private static readonly CieXyzAndCieXyyConverter CieXyzAndCieXyyConverter = new CieXyzAndCieXyyConverter(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 6ecb33ffc9..b29e249055 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { private static readonly CieLabToCieXyzConverter CieLabToCieXyzConverter = new CieLabToCieXyzConverter(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index f8628e39b6..8aaaad0ae8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { private static readonly CmykAndRgbConverter CmykAndRgbConverter = new CmykAndRgbConverter(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index 8832be9174..a91f5a66d1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { private static readonly HslAndRgbConverter HslAndRgbConverter = new HslAndRgbConverter(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index 8269014276..c03239e164 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { private static readonly HsvAndRgbConverter HsvAndRgbConverter = new HsvAndRgbConverter(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index 27c5589de4..a4a9aa24d1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { /// /// Converts a into a diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index 2f65841bc2..f4a628cb8c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { private static readonly RgbToLinearRgbConverter RgbToLinearRgbConverter = new RgbToLinearRgbConverter(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index 052aeb6d15..a328057ac2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { /// /// Converts a into a diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index 5ef7934481..31ec3dd401 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { private static readonly LinearRgbToRgbConverter LinearRgbToRgbConverter = new LinearRgbToRgbConverter(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 4bb3db82c9..2521114fb4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Allows conversion to . /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { private static readonly YCbCrAndRgbConverter YCbCrAndRgbConverter = new YCbCrAndRgbConverter(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index c422abfade..7de590e225 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// Converts between color spaces ensuring that the color is adapted using chromatic adaptation. /// - internal partial class ColorSpaceConverter + public partial class ColorSpaceConverter { /// /// The default whitepoint used for converting to CieLab diff --git a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs index dfba4b9269..e84b8bf255 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// A linear transformation of a source color (XS, YS, ZS) into a destination color (XD, YD, ZD) by a linear transformation [M] /// which is dependent on the source reference white (XWS, YWS, ZWS) and the destination reference white (XWD, YWD, ZWD). /// - internal interface IChromaticAdaptation + public interface IChromaticAdaptation { /// /// Performs a linear transformation of a source color in to the destination color. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs index f19c07d44a..05d8ef551c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal class CieLchToCieLabConverter : IColorConversion + internal sealed class CieLchToCieLabConverter : IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs index 7a5d404b91..c82ad4ad92 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal class CieLabToCieLchConverter : IColorConversion + internal sealed class CieLabToCieLchConverter : IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs index 2225591aa0..88d965b5bb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal class CieLabToCieXyzConverter : IColorConversion + internal sealed class CieLabToCieXyzConverter : IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs index 75f1a0bb87..3428dd0ae2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal class CieLchuvToCieLuvConverter : IColorConversion + internal sealed class CieLchuvToCieLuvConverter : IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs index 71935547e0..9670a704e1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal class CieLuvToCieLchuvConverter : IColorConversion + internal sealed class CieLuvToCieLchuvConverter : IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs index cb16565790..9874a82907 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal class CieLuvToCieXyzConverter : IColorConversion + internal sealed class CieLuvToCieXyzConverter : IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs index ff7f270331..856cd16322 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Color converter between CIE XYZ and CIE xyY /// for formulas. /// - internal class CieXyzAndCieXyyConverter : IColorConversion, IColorConversion + internal sealed class CieXyzAndCieXyyConverter : IColorConversion, IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs index e3a031e82c..405ccc8194 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Color converter between CIE XYZ and LMS /// - internal class CieXyzAndLmsConverter : IColorConversion, IColorConversion + internal sealed class CieXyzAndLmsConverter : IColorConversion, IColorConversion { /// /// Default transformation matrix used, when no other is set. (Bradford) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs index 24c89e1da6..1e4ad96b0d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal class CieXyzToCieLabConverter : IColorConversion + internal sealed class CieXyzToCieLabConverter : IColorConversion { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs index ef3c976c3b..614d3973e1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal class CieXyzToCieLuvConverter : IColorConversion + internal sealed class CieXyzToCieLuvConverter : IColorConversion { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs index 743d133edf..d990d3ef6a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Color converter between CieXyz and HunterLab /// - internal class CieXyzToHunterLabConverter : CieXyzAndHunterLabConverterBase, IColorConversion + internal sealed class CieXyzToHunterLabConverter : CieXyzAndHunterLabConverterBase, IColorConversion { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs index 26d15beb3c..6b16e42282 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Color converter between CMYK and Rgb /// - internal class CmykAndRgbConverter : IColorConversion, IColorConversion + internal sealed class CmykAndRgbConverter : IColorConversion, IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs index d8d152a966..45ad0d3196 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// /// - internal class GammaCompanding : ICompanding + public sealed class GammaCompanding : ICompanding { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs index 0cc5e8fd7a..1a885d6be5 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Color converter between HSL and Rgb /// See for formulas. /// - internal class HslAndRgbConverter : IColorConversion, IColorConversion + internal sealed class HslAndRgbConverter : IColorConversion, IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs index 0a14ce2f12..ed7c6dd2ca 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Color converter between HSV and Rgb /// See for formulas. /// - internal class HsvAndRgbConverter : IColorConversion, IColorConversion + internal sealed class HsvAndRgbConverter : IColorConversion, IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs index 241a060923..a7ba26270c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Color converter between HunterLab and CieXyz /// - internal class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase, IColorConversion + internal sealed class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase, IColorConversion { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs index bded652b48..6e87769d79 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// /// - internal class LCompanding : ICompanding + public sealed class LCompanding : ICompanding { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs index a985f8ed54..a38a45cb1c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs @@ -8,12 +8,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Color converter between LinearRgb and Rgb /// - internal class LinearRgbToRgbConverter : IColorConversion + internal sealed class LinearRgbToRgbConverter : IColorConversion { /// public Rgb Convert(in LinearRgb input) { - Vector3 vector = input.ToVector3(); + var vector = input.ToVector3(); vector.X = input.WorkingSpace.Companding.Compress(vector.X); vector.Y = input.WorkingSpace.Companding.Compress(vector.Y); vector.Z = input.WorkingSpace.Companding.Compress(vector.Z); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs index e7385054b9..aef0b560e5 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// DISCo, Department of Informatics, Systems and Communication, University of Milan-Bicocca, viale Sarca 336, 20126 Milan, Italy /// https://web.stanford.edu/~sujason/ColorBalancing/Papers/Two%20New%20von%20Kries%20Based%20Chromatic%20Adaptation.pdf /// - internal static class LmsAdaptationMatrix + public static class LmsAdaptationMatrix { /// /// Von Kries chromatic adaptation transform matrix (Hunt-Pointer-Estevez adjusted for D65) @@ -25,9 +25,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public static readonly Matrix4x4 VonKriesHPEAdjusted = Matrix4x4.Transpose(new Matrix4x4 { - M11 = 0.40024F, M12 = 0.7076F, M13 = -0.08081F, - M21 = -0.2263F, M22 = 1.16532F, M23 = 0.0457F, - M31 = 0, M32 = 0, M33 = 0.91822F, + M11 = 0.40024F, + M12 = 0.7076F, + M13 = -0.08081F, + M21 = -0.2263F, + M22 = 1.16532F, + M23 = 0.0457F, + M31 = 0, + M32 = 0, + M33 = 0.91822F, M44 = 1F // Important for inverse transforms. }); @@ -37,9 +43,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public static readonly Matrix4x4 VonKriesHPE = Matrix4x4.Transpose(new Matrix4x4 { - M11 = 0.3897F, M12 = 0.6890F, M13 = -0.0787F, - M21 = -0.2298F, M22 = 1.1834F, M23 = 0.0464F, - M31 = 0, M32 = 0, M33 = 1F, + M11 = 0.3897F, + M12 = 0.6890F, + M13 = -0.0787F, + M21 = -0.2298F, + M22 = 1.1834F, + M23 = 0.0464F, + M31 = 0, + M32 = 0, + M33 = 1F, M44 = 1F }); @@ -54,9 +66,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public static readonly Matrix4x4 Bradford = Matrix4x4.Transpose(new Matrix4x4 { - M11 = 0.8951F, M12 = 0.2664F, M13 = -0.1614F, - M21 = -0.7502F, M22 = 1.7135F, M23 = 0.0367F, - M31 = 0.0389F, M32 = -0.0685F, M33 = 1.0296F, + M11 = 0.8951F, + M12 = 0.2664F, + M13 = -0.1614F, + M21 = -0.7502F, + M22 = 1.7135F, + M23 = 0.0367F, + M31 = 0.0389F, + M32 = -0.0685F, + M33 = 1.0296F, M44 = 1F }); @@ -65,35 +83,53 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public static readonly Matrix4x4 BradfordSharp = Matrix4x4.Transpose(new Matrix4x4 - { - M11 = 1.2694F, M12 = -0.0988F, M13 = -0.1706F, - M21 = -0.8364F, M22 = 1.8006F, M23 = 0.0357F, - M31 = 0.0297F, M32 = -0.0315F, M33 = 1.0018F, - M44 = 1F - }); + { + M11 = 1.2694F, + M12 = -0.0988F, + M13 = -0.1706F, + M21 = -0.8364F, + M22 = 1.8006F, + M23 = 0.0357F, + M31 = 0.0297F, + M32 = -0.0315F, + M33 = 1.0018F, + M44 = 1F + }); /// /// CMCCAT2000 (fitted from all available color data sets) /// public static readonly Matrix4x4 CMCCAT2000 = Matrix4x4.Transpose(new Matrix4x4 - { - M11 = 0.7982F, M12 = 0.3389F, M13 = -0.1371F, - M21 = -0.5918F, M22 = 1.5512F, M23 = 0.0406F, - M31 = 0.0008F, M32 = 0.239F, M33 = 0.9753F, - M44 = 1F - }); + { + M11 = 0.7982F, + M12 = 0.3389F, + M13 = -0.1371F, + M21 = -0.5918F, + M22 = 1.5512F, + M23 = 0.0406F, + M31 = 0.0008F, + M32 = 0.239F, + M33 = 0.9753F, + M44 = 1F + }); /// /// CAT02 (optimized for minimizing CIELAB differences) /// public static readonly Matrix4x4 CAT02 = Matrix4x4.Transpose(new Matrix4x4 - { - M11 = 0.7328F, M12 = 0.4296F, M13 = -0.1624F, - M21 = -0.7036F, M22 = 1.6975F, M23 = 0.0061F, - M31 = 0.0030F, M32 = 0.0136F, M33 = 0.9834F, - M44 = 1F - }); + { + M11 = 0.7328F, + M12 = 0.4296F, + M13 = -0.1624F, + M21 = -0.7036F, + M22 = 1.6975F, + M23 = 0.0061F, + M31 = 0.0030F, + M32 = 0.0136F, + M33 = 0.9834F, + M44 = 1F + }); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs index 70e64256f8..758f5f7dcc 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Represents the chromaticity coordinates of RGB primaries. /// One of the specifiers of . /// - internal readonly struct RgbPrimariesChromaticityCoordinates : IEquatable + public readonly struct RgbPrimariesChromaticityCoordinates : IEquatable { /// /// Initializes a new instance of the struct. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs index ffa006bc0e..8fea53c8b9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// For 10-bits, companding is identical to /// - internal class Rec2020Companding : ICompanding + public sealed class Rec2020Companding : ICompanding { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs index 9589b9b683..c5ed1076db 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// http://en.wikipedia.org/wiki/Rec._709 /// - internal class Rec709Companding : ICompanding + public sealed class Rec709Companding : ICompanding { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs index 101d135f57..d2ba91ce28 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Trivial implementation of /// - internal class RgbWorkingSpace : IEquatable + public class RgbWorkingSpace : IEquatable { /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs index 65e87a599c..98938e6560 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// /// - internal class SRgbCompanding : ICompanding + public sealed class SRgbCompanding : ICompanding { /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs index 5d2cd85ba2..cb7071adf1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Color converter between YCbCr and Rgb /// See for formulas. /// - internal class YCbCrAndRgbConverter : IColorConversion, IColorConversion + internal sealed class YCbCrAndRgbConverter : IColorConversion, IColorConversion { private static readonly Vector3 MaxBytes = new Vector3(255F); diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index f3d74b6f80..306f013ed3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// Transformation described here: /// http://www.brucelindbloom.com/index.html?Eqn_ChromAdapt.html /// - internal class VonKriesChromaticAdaptation : IChromaticAdaptation + public class VonKriesChromaticAdaptation : IChromaticAdaptation { private readonly CieXyzAndLmsConverter converter; @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// Initializes a new instance of the class. /// /// The color converter - public VonKriesChromaticAdaptation(CieXyzAndLmsConverter converter) + internal VonKriesChromaticAdaptation(CieXyzAndLmsConverter converter) { this.converter = converter; } diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index 14dfc5d1ac..04d8974f01 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents a Hsl (hue, saturation, lightness) color. /// - internal readonly struct Hsl : IEquatable + public readonly struct Hsl : IEquatable { /// /// Max range used for clamping. diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index 1035f94bf2..54fd0eee2e 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents a HSV (hue, saturation, value) color. Also known as HSB (hue, saturation, brightness). /// - internal readonly struct Hsv : IEquatable + public readonly struct Hsv : IEquatable { /// /// Max range used for clamping. diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index 2f8da5a9a3..15f3acc95f 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Represents an Hunter LAB color. /// /// - internal readonly struct HunterLab : IEquatable + public readonly struct HunterLab : IEquatable { /// /// D50 standard illuminant. diff --git a/src/ImageSharp/ColorSpaces/IAlmostEquatable.cs b/src/ImageSharp/ColorSpaces/IAlmostEquatable.cs deleted file mode 100644 index 08c2dafbc6..0000000000 --- a/src/ImageSharp/ColorSpaces/IAlmostEquatable.cs +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; - -namespace SixLabors.ImageSharp.ColorSpaces -{ - /// - /// Defines a generalized method that a value type or class implements to create - /// a type-specific method for determining approximate equality of instances. - /// - /// The type of objects to compare. - /// The object specifying the type to specify precision with. - internal interface IAlmostEquatable - where TPrecision : struct, IComparable - { - /// - /// Indicates whether the current object is equal to another object of the same type - /// when compared to the specified precision level. - /// - /// An object to compare with this object. - /// The object specifying the level of precision. - /// - /// true if the current object is equal to the other parameter; otherwise, false. - /// - bool AlmostEquals(TPixel other, TPrecision precision); - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/ICompanding.cs b/src/ImageSharp/ColorSpaces/ICompanding.cs index c16281b23b..8d81501b7e 100644 --- a/src/ImageSharp/ColorSpaces/ICompanding.cs +++ b/src/ImageSharp/ColorSpaces/ICompanding.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Used for conversion to and backwards. /// See also: /// - internal interface ICompanding + public interface ICompanding { /// /// Expands a companded channel to its linear equivalent with respect to the energy. diff --git a/src/ImageSharp/ColorSpaces/Illuminants.cs b/src/ImageSharp/ColorSpaces/Illuminants.cs index 85c4063bf4..ed385e02cd 100644 --- a/src/ImageSharp/ColorSpaces/Illuminants.cs +++ b/src/ImageSharp/ColorSpaces/Illuminants.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Descriptions taken from: /// http://en.wikipedia.org/wiki/Standard_illuminant /// - internal static class Illuminants + public static class Illuminants { /// /// Incandescent / Tungsten diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index e9e06c0bbb..343c6f1c54 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents an linear Rgb color with specified working space /// - internal readonly struct LinearRgb : IEquatable + public readonly struct LinearRgb : IEquatable { /// /// The default LinearRgb working space. diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 5c471649d3..3f55d8891d 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// named after their responsivity (sensitivity) at long, medium and short wavelengths. /// /// - internal readonly struct Lms : IEquatable + public readonly struct Lms : IEquatable { /// /// Gets the L long component. diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 8faf4f2b59..bec279ad3f 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Represents an RGB color with specified working space. /// - internal readonly struct Rgb : IEquatable + public readonly struct Rgb : IEquatable { /// /// The default rgb working space @@ -97,20 +97,28 @@ namespace SixLabors.ImageSharp.ColorSpaces this.WorkingSpace = workingSpace; } + /// + /// Allows the implicit conversion of an instance of to a + /// . + /// + /// The instance of to convert. + /// An instance of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Rgb(Rgb24 color) + { + return new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); + } + /// /// Allows the implicit conversion of an instance of to a /// . /// - /// - /// The instance of to convert. - /// - /// - /// An instance of . - /// + /// The instance of to convert. + /// An instance of . [MethodImpl(MethodImplOptions.AggressiveInlining)] public static implicit operator Rgb(Rgba32 color) { - return new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); + return new Rgba32(color.R / 255F, color.G / 255F, color.B / 255F); } /// diff --git a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs index a2561640ac..62bf7d6292 100644 --- a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs +++ b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Chromaticity coordinates taken from: /// /// - internal static class RgbWorkingSpaces + public static class RgbWorkingSpaces { /// /// sRgb working space. diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index f684f598b0..88f7cac4c3 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// /// - internal readonly struct YCbCr : IEquatable + public readonly struct YCbCr : IEquatable { /// /// Vector which is used in clamping to the max value. diff --git a/src/ImageSharp/PixelFormats/Rgb24.cs b/src/ImageSharp/PixelFormats/Rgb24.cs index d7e1c47ec0..24c311d0d3 100644 --- a/src/ImageSharp/PixelFormats/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/Rgb24.cs @@ -50,6 +50,21 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = b; } + /// + /// Allows the implicit conversion of an instance of to a + /// . + /// + /// The instance of to convert. + /// An instance of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Rgb24(ColorSpaces.Rgb color) + { + var vector = new Vector4(color.ToVector3(), 1); + Rgb24 rgb = default; + rgb.PackFromScaledVector4(vector); + return rgb; + } + /// public PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 79794ee462..e38368e620 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -206,6 +206,21 @@ namespace SixLabors.ImageSharp.PixelFormats set => this.Rgba = value; } + /// + /// Allows the implicit conversion of an instance of to a + /// . + /// + /// The instance of to convert. + /// An instance of . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Rgba32(ColorSpaces.Rgb color) + { + var vector = new Vector4(color.ToVector3(), 1); + Rgba32 rgba = default; + rgba.PackFromScaledVector4(vector); + return rgba; + } + /// /// Compares two objects for equality. /// From 72b3aff65c541d9db930fbddb76b39f81a43928f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 27 Jul 2018 18:59:39 +0100 Subject: [PATCH 022/185] Add companding tests --- .../{ => Conversion}/ICompanding.cs | 4 +- .../Colorspaces/ColorSpaceEqualityTests.cs | 5 -- .../ApproximateColorspaceComparer.cs | 2 +- .../CieLabAndCieLchConversionTests.cs | 2 +- .../CieLuvAndCieLchuvConversionTests.cs | 2 +- .../CieXyzAndCieLabConversionTest.cs | 2 +- .../CieXyzAndCieLuvConversionTest.cs | 2 +- .../CieXyzAndCieXyyConversionTest.cs | 2 +- .../CieXyzAndHunterLabConversionTest.cs | 2 +- .../CieXyzAndLmsConversionTest.cs | 2 +- .../ColorConverterAdaptTest.cs | 2 +- .../Colorspaces/Conversion/CompandingTests.cs | 57 +++++++++++++++++++ .../RgbAndCieXyzConversionTest.cs | 2 +- .../RgbAndCmykConversionTest.cs | 2 +- .../RgbAndHslConversionTest.cs | 2 +- .../RgbAndHsvConversionTest.cs | 2 +- .../RgbAndYCbCrConversionTest.cs | 2 +- .../Formats/Jpg/JpegColorConverterTests.cs | 2 +- 18 files changed, 73 insertions(+), 23 deletions(-) rename src/ImageSharp/ColorSpaces/{ => Conversion}/ICompanding.cs (92%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/ApproximateColorspaceComparer.cs (99%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/CieLabAndCieLchConversionTests.cs (98%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/CieLuvAndCieLchuvConversionTests.cs (98%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/CieXyzAndCieLabConversionTest.cs (98%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/CieXyzAndCieLuvConversionTest.cs (98%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/CieXyzAndCieXyyConversionTest.cs (97%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/CieXyzAndHunterLabConversionTest.cs (98%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/CieXyzAndLmsConversionTest.cs (98%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/ColorConverterAdaptTest.cs (98%) create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/RgbAndCieXyzConversionTest.cs (99%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/RgbAndCmykConversionTest.cs (98%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/RgbAndHslConversionTest.cs (98%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/RgbAndHsvConversionTest.cs (98%) rename tests/ImageSharp.Tests/Colorspaces/{ => Conversion}/RgbAndYCbCrConversionTest.cs (97%) diff --git a/src/ImageSharp/ColorSpaces/ICompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/ICompanding.cs similarity index 92% rename from src/ImageSharp/ColorSpaces/ICompanding.cs rename to src/ImageSharp/ColorSpaces/Conversion/ICompanding.cs index 8d81501b7e..55a7569ffa 100644 --- a/src/ImageSharp/ColorSpaces/ICompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ICompanding.cs @@ -1,9 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; - -namespace SixLabors.ImageSharp.ColorSpaces +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Pair of companding functions for . diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs index 466c1dca1b..1e629b4553 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs @@ -1,15 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Collections.Generic; -using System.Linq; using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; using Xunit; -// ReSharper disable InconsistentNaming -// TODO: This needs to be refactored so that it uses a serializable type once the colorspace code is public namespace SixLabors.ImageSharp.Tests.Colorspaces { /// diff --git a/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs similarity index 99% rename from tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs index 88aa572ee5..169a907b14 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ApproximateColorspaceComparer.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs @@ -5,7 +5,7 @@ using System.Collections.Generic; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Allows the approximate comparison of colorspace component values. diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs index de63a3dbf0..d3d7598251 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs index cb83340877..be510f95d8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLuvAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs index 763c607700..66f7e75ada 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs index df80db2d29..a6a7ee7aec 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieLuvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs similarity index 97% rename from tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs index 2686a8228f..3f5ea4cfd8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndCieXyyConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieXyyConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs index 6e547e9e42..2251777927 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndHunterLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs index eb7e8fa86d..6b128eff8c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs index aa7325a51a..f5dc6f6118 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces.Conversion; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests methods. diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs new file mode 100644 index 0000000000..adf0263a06 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs @@ -0,0 +1,57 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests various companding algorithms. Numbers are hand calculated from formulas online. + /// TODO: Oddly the formula for converting to/from Rec 2020 and 709 from Wikipedia seems to cause the value to + /// fail a round trip. They're large spaces so this is a surprise. More reading required!! + /// + public class CompandingTests + { + private static readonly ApproximateFloatComparer FloatComparer = new ApproximateFloatComparer(.00001F); + + [Fact] + public void Rec2020CompandingIsCorrect() + { + CompandingIsCorrectImpl(new Rec2020Companding(), .667F, .4484759F, .3937096F); + } + + [Fact] + public void Rec709CompandingIsCorrect() + { + CompandingIsCorrectImpl(new Rec709Companding(), .667F, .4483577F, .3937451F); + } + + [Fact] + public void SRgbCompandingIsCorrect() + { + CompandingIsCorrectImpl(new SRgbCompanding(), .667F, .40242353F, .667F); + } + + [Fact] + public void GammaCompandingIsCorrect() + { + CompandingIsCorrectImpl(new GammaCompanding(2.2F), .667F, .41027668F, .667F); + } + + [Fact] + public void LCompandingIsCorrect() + { + CompandingIsCorrectImpl(new LCompanding(), .667F, .36236193F, .58908917F); + } + + private static void CompandingIsCorrectImpl(ICompanding companding, float input, float expanded, float compressed) + { + float e = companding.Expand(input); + float c = companding.Compress(e); + + Assert.Equal(expanded, e, FloatComparer); + Assert.Equal(compressed, c, FloatComparer); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs similarity index 99% rename from tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs index 92ab75a8a6..ea1d0db00f 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndCieXyzConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs index a8a9a05674..2b03ee9883 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndCmykConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCmykConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs index ba7aab5ea5..22f5c6d514 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndHslConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHslConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs similarity index 98% rename from tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs index 89829e9d97..e84ce97237 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndHsvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndHsvConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs similarity index 97% rename from tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs index 2e66dd7b02..f5c7dbae66 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbAndYCbCrConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndYCbCrConversionTest.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// /// Tests - conversions. diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs index 7c2eb82383..75dc0081e6 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegColorConverterTests.cs @@ -8,7 +8,7 @@ using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters; -using SixLabors.ImageSharp.Tests.Colorspaces; +using SixLabors.ImageSharp.Tests.Colorspaces.Conversion; using SixLabors.Memory; using Xunit; From 7a9efabaea05087416de18fcb0474ca3c002e157 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 28 Jul 2018 15:53:35 +0100 Subject: [PATCH 023/185] Cleanup ToString() and remove unused operator --- src/ImageSharp/ColorSpaces/CieLab.cs | 18 +++-- src/ImageSharp/ColorSpaces/CieLch.cs | 22 +++---- src/ImageSharp/ColorSpaces/CieLchuv.cs | 16 ++--- src/ImageSharp/ColorSpaces/CieLuv.cs | 18 +++-- .../CieXyChromaticityCoordinates.cs | 14 ++-- src/ImageSharp/ColorSpaces/CieXyy.cs | 14 ++-- src/ImageSharp/ColorSpaces/CieXyz.cs | 14 ++-- src/ImageSharp/ColorSpaces/Cmyk.cs | 16 ++--- src/ImageSharp/ColorSpaces/Hsl.cs | 16 ++--- src/ImageSharp/ColorSpaces/Hsv.cs | 66 ++----------------- src/ImageSharp/ColorSpaces/HunterLab.cs | 18 +++-- src/ImageSharp/ColorSpaces/LinearRgb.cs | 22 +++---- src/ImageSharp/ColorSpaces/Lms.cs | 16 ++--- src/ImageSharp/ColorSpaces/Rgb.cs | 24 ++++--- src/ImageSharp/ColorSpaces/YCbCr.cs | 14 ++-- 15 files changed, 114 insertions(+), 194 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 305a3da4fb..5ab133cf90 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The a (green - magenta) component. /// The b (blue - yellow) component. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLab(float l, float a, float b) : this(l, a, b, DefaultWhitePoint) { @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The a (green - magenta) component. /// The b (blue - yellow) component. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLab(float l, float a, float b, CieXyz whitePoint) { this.L = l; @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l, a, b components. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLab(Vector3 vector) : this(vector, DefaultWhitePoint) { @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l, a, b components. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLab(Vector3 vector, CieXyz whitePoint) : this() { @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(CieLab left, CieLab right) => left.Equals(right); /// @@ -116,7 +116,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(CieLab left, CieLab right) => !left.Equals(right); /// @@ -131,16 +131,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "CieLab [Empty]" - : $"CieLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; + return $"CieLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; } /// public override bool Equals(object obj) => obj is CieLab other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieLab other) { return this.L.Equals(other.L) diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index 793b68879a..d2b3d378df 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The chroma, relative saturation. /// The hue in degrees. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLch(float l, float c, float h) : this(l, c, h, DefaultWhitePoint) { @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The chroma, relative saturation. /// The hue in degrees. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLch(float l, float c, float h, CieXyz whitePoint) { this.L = l; @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l, c, h components. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLch(Vector3 vector) : this(vector, DefaultWhitePoint) { @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l, c, h components. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLch(Vector3 vector, CieXyz whitePoint) { this.L = vector.X; @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(CieLch left, CieLch right) { return left.Equals(right); @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(CieLch left, CieLch right) => !left.Equals(right); /// @@ -133,17 +133,15 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "CieLch [Empty]" - : $"CieLch [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}]"; + return $"CieLch [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}]"; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override bool Equals(object obj) => obj is CieLch other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieLch other) { return this.L.Equals(other.L) @@ -159,7 +157,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// A value ranging from 0 to 100. /// /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public float Saturation() { float result = 100 * (this.C / this.L); diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index 1a592c93f8..d46c93c75e 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The chroma, relative saturation. /// The hue in degrees. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLchuv(float l, float c, float h) : this(l, c, h, DefaultWhitePoint) { @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The chroma, relative saturation. /// The hue in degrees. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLchuv(float l, float c, float h, CieXyz whitePoint) { this.L = l; @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l, c, h components. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLchuv(Vector3 vector) : this(vector, DefaultWhitePoint) { @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l, c, h components. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLchuv(Vector3 vector, CieXyz whitePoint) : this() { @@ -129,16 +129,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "CieLchuv [Empty]" - : $"CieLchuv [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}"; + return $"CieLchuv [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}"; } /// public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieLchuv other) { return this.L.Equals(other.L) @@ -154,7 +152,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// A value ranging from 0 to 100. /// /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public float Saturation() { float result = 100 * (this.C / this.L); diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index f6b2cd1103..edf865d3c5 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The blue-yellow chromaticity coordinate of the given whitepoint. /// The red-green chromaticity coordinate of the given whitepoint. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLuv(float l, float u, float v) : this(l, u, v, DefaultWhitePoint) { @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The blue-yellow chromaticity coordinate of the given whitepoint. /// The red-green chromaticity coordinate of the given whitepoint. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLuv(float l, float u, float v, CieXyz whitePoint) { this.L = l; @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l, u, v components. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLuv(Vector3 vector) : this(vector, DefaultWhitePoint) { @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l, u, v components. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLuv(Vector3 vector, CieXyz whitePoint) { this.L = vector.X; @@ -106,7 +106,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(CieLuv left, CieLuv right) => left.Equals(right); /// @@ -117,7 +117,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(CieLuv left, CieLuv right) => !left.Equals(right); /// @@ -132,16 +132,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "CieLuv [ Empty ]" - : $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]"; + return $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]"; } /// public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieLuv other) { return this.L.Equals(other.L) diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs index db292041bc..9b258eda78 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Chromaticity coordinate x (usually from 0 to 1) /// Chromaticity coordinate y (usually from 0 to 1) - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieXyChromaticityCoordinates(float x, float y) { this.X = x; @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right) { return left.Equals(right); @@ -62,29 +62,27 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right) { return !left.Equals(right); } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode()); /// public override string ToString() { - return this.Equals(default) - ? "CieXyChromaticityCoordinates [Empty]" - : $"CieXyChromaticityCoordinates [ X={this.X:#0.##}, Y={this.Y:#0.##}]"; + return $"CieXyChromaticityCoordinates [ X={this.X:#0.##}, Y={this.Y:#0.##}]"; } /// public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieXyChromaticityCoordinates other) => this.X.Equals(other.X) && this.Y.Equals(other.Y); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index 9d2fed225d..831c357027 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The x chroma component. /// The y chroma component. /// The y luminance component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieXyy(float x, float y, float yl) { // Not clamping as documentation about this space seems to indicate "usual" ranges @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Initializes a new instance of the struct. /// /// The vector representing the x, y, Y components. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieXyy(Vector3 vector) : this() { @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(CieXyy left, CieXyy right) => left.Equals(right); /// @@ -79,7 +79,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(CieXyy left, CieXyy right) => !left.Equals(right); /// @@ -93,9 +93,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "CieXyy [ Empty ]" - : $"CieXyy [ X={this.X:#0.##}, Y={this.Y:#0.##}, Yl={this.Yl:#0.##} ]"; + return $"CieXyy [ X={this.X:#0.##}, Y={this.Y:#0.##}, Yl={this.Yl:#0.##} ]"; } /// @@ -105,7 +103,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieXyy other) { return this.X.Equals(other.X) diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index 5d4acbcfda..a5d409f6b3 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// X is a mix (a linear combination) of cone response curves chosen to be nonnegative /// The y luminance component. /// Z is quasi-equal to blue stimulation, or the S cone of the human eye. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieXyz(float x, float y, float z) : this(new Vector3(x, y, z)) { @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(CieXyz left, CieXyz right) { return left.Equals(right); @@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(CieXyz left, CieXyz right) { return !left.Equals(right); @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Returns a new representing this instance. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector3 ToVector3() => new Vector3(this.X, this.Y, this.Z); /// @@ -107,16 +107,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "CieXyz [ Empty ]" - : $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]"; + return $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]"; } /// public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(CieXyz other) { return this.X.Equals(other.X) diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index f862151890..bc1131aa37 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The magenta component. /// The yellow component. /// The keyline black component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Cmyk(float c, float m, float y, float k) : this(new Vector4(c, m, y, k)) { @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Initializes a new instance of the struct. /// /// The vector representing the c, m, y, k components. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Cmyk(Vector4 vector) { vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(Cmyk left, Cmyk right) => left.Equals(right); /// @@ -82,11 +82,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Cmyk left, Cmyk right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() { int hash = this.C.GetHashCode(); @@ -98,16 +98,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "Cmyk [Empty]" - : $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]"; + return $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]"; } /// public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Cmyk other) { return this.C.Equals(other.C) diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index 04d8974f01..c6e1e4f9d4 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The h hue component. /// The s saturation component. /// The l value (lightness) component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Hsl(float h, float s, float l) : this(new Vector3(h, s, l)) { @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Initializes a new instance of the struct. /// /// The vector representing the h, s, l components. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Hsl(Vector3 vector) { vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(Hsl left, Hsl right) => left.Equals(right); /// @@ -81,11 +81,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Hsl left, Hsl right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() { int hash = this.H.GetHashCode(); @@ -96,16 +96,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "Hsl [ Empty ]" - : $"Hsl [ H={this.H:#0.##}, S={this.S:#0.##}, L={this.L:#0.##} ]"; + return $"Hsl [ H={this.H:#0.##}, S={this.S:#0.##}, L={this.L:#0.##} ]"; } /// public override bool Equals(object obj) => obj is Hsl other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Hsl other) { return this.H.Equals(other.H) diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index 54fd0eee2e..5fdc287ced 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The h hue component. /// The s saturation component. /// The v value (brightness) component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Hsv(float h, float s, float v) : this(new Vector3(h, s, v)) { @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Initializes a new instance of the struct. /// /// The vector representing the h, s, v components. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Hsv(Vector3 vector) { vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); @@ -63,56 +63,6 @@ namespace SixLabors.ImageSharp.ColorSpaces this.V = vector.Z; } - /// - /// Allows the implicit conversion of an instance of to a - /// . - /// - /// The instance of to convert. - /// - /// An instance of . - /// - public static implicit operator Hsv(Rgba32 color) - { - float r = color.R / 255F; - float g = color.G / 255F; - float b = color.B / 255F; - - float max = MathF.Max(r, MathF.Max(g, b)); - float min = MathF.Min(r, MathF.Min(g, b)); - float chroma = max - min; - float h = 0; - float s = 0; - float v = max; - - if (MathF.Abs(chroma) < Constants.Epsilon) - { - return new Hsv(0, s, v); - } - - if (MathF.Abs(r - max) < Constants.Epsilon) - { - h = (g - b) / chroma; - } - else if (MathF.Abs(g - max) < Constants.Epsilon) - { - h = 2 + ((b - r) / chroma); - } - else if (MathF.Abs(b - max) < Constants.Epsilon) - { - h = 4 + ((r - g) / chroma); - } - - h *= 60; - if (h < 0.0) - { - h += 360; - } - - s = chroma / v; - - return new Hsv(h, s, v); - } - /// /// Compares two objects for equality. /// @@ -121,7 +71,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(Hsv left, Hsv right) => left.Equals(right); /// @@ -132,11 +82,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Hsv left, Hsv right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() { int hash = this.H.GetHashCode(); @@ -147,16 +97,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "Hsv [ Empty ]" - : $"Hsv [ H={this.H:#0.##}, S={this.S:#0.##}, V={this.V:#0.##} ]"; + return $"Hsv [ H={this.H:#0.##}, S={this.S:#0.##}, V={this.V:#0.##} ]"; } /// public override bool Equals(object obj) => obj is Hsv other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Hsv other) { return this.H.Equals(other.H) diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index 15f3acc95f..d458fa7895 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The a (green - magenta) component. /// The b (blue - yellow) component. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public HunterLab(float l, float a, float b) : this(new Vector3(l, a, b), DefaultWhitePoint) { @@ -63,7 +63,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The a (green - magenta) component. /// The b (blue - yellow) component. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public HunterLab(float l, float a, float b, CieXyz whitePoint) : this(new Vector3(l, a, b), whitePoint) { @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l, a, b components. /// Uses as white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public HunterLab(Vector3 vector) : this(vector, DefaultWhitePoint) { @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the l a b components. /// The reference white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public HunterLab(Vector3 vector, CieXyz whitePoint) { // TODO: Clamp? @@ -113,11 +113,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HunterLab left, HunterLab right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() { int hash = this.L.GetHashCode(); @@ -129,16 +129,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "HunterLab [Empty]" - : $"HunterLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; + return $"HunterLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; } /// public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(HunterLab other) { return this.L.Equals(other.L) diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index 343c6f1c54..e7c74cb2dd 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -47,7 +47,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The red component ranging between 0 and 1. /// The green component ranging between 0 and 1. /// The blue component ranging between 0 and 1. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public LinearRgb(float r, float g, float b) : this(new Vector3(r, g, b)) { @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The green component ranging between 0 and 1. /// The blue component ranging between 0 and 1. /// The rgb working space. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public LinearRgb(float r, float g, float b, RgbWorkingSpace workingSpace) : this(new Vector3(r, g, b), workingSpace) { @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Initializes a new instance of the struct. /// /// The vector representing the r, g, b components. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public LinearRgb(Vector3 vector) : this(vector, DefaultWorkingSpace) { @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the r, g, b components. /// The LinearRgb working space. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public LinearRgb(Vector3 vector, RgbWorkingSpace workingSpace) { // Clamp to 0-1 range. @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(LinearRgb left, LinearRgb right) => left.Equals(right); /// @@ -111,18 +111,18 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(LinearRgb left, LinearRgb right) => !left.Equals(right); /// /// Returns a new representing this instance. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector3 ToVector3() => new Vector3(this.R, this.G, this.B); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() { int hash = this.R.GetHashCode(); @@ -133,16 +133,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "LinearRgb [ Empty ]" - : $"LinearRgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; + return $"LinearRgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; } /// public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(LinearRgb other) { return this.R.Equals(other.R) diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 3f55d8891d..0204a0ebcf 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// L represents the responsivity at long wavelengths. /// M represents the responsivity at medium wavelengths. /// S represents the responsivity at short wavelengths. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Lms(float l, float m, float s) { this.L = l; @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Initializes a new instance of the struct. /// /// The vector representing the l, m, s components. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Lms(Vector3 vector) { // Not clamping as documentation about this space seems to indicate "usual" ranges @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(Lms left, Lms right) => left.Equals(right); /// @@ -78,14 +78,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Lms left, Lms right) => !left.Equals(right); /// /// Returns a new representing this instance. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector3 ToVector3() => new Vector3(this.L, this.M, this.S); /// @@ -99,16 +99,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "Lms [ Empty ]" - : $"Lms [ L={this.L:#0.##}, M={this.M:#0.##}, S={this.S:#0.##} ]"; + return $"Lms [ L={this.L:#0.##}, M={this.M:#0.##}, S={this.S:#0.##} ]"; } /// public override bool Equals(object obj) => obj is Lms other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Lms other) { return this.L.Equals(other.L) diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index bec279ad3f..db2c8e86b5 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The red component ranging between 0 and 1. /// The green component ranging between 0 and 1. /// The blue component ranging between 0 and 1. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb(float r, float g, float b) : this(r, g, b, DefaultWorkingSpace) { @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The green component ranging between 0 and 1. /// The blue component ranging between 0 and 1. /// The rgb working space. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb(float r, float g, float b, RgbWorkingSpace workingSpace) { // Clamp to 0-1 range. @@ -75,7 +75,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Initializes a new instance of the struct. /// /// The vector representing the r, g, b components. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb(Vector3 vector) : this(vector, DefaultWorkingSpace) { @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The vector representing the r, g, b components. /// The rgb working space. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb(Vector3 vector, RgbWorkingSpace workingSpace) { // Clamp to 0-1 range. @@ -103,7 +103,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The instance of to convert. /// An instance of . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static implicit operator Rgb(Rgb24 color) { return new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); @@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The instance of to convert. /// An instance of . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static implicit operator Rgb(Rgba32 color) { return new Rgba32(color.R / 255F, color.G / 255F, color.B / 255F); @@ -133,7 +133,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is equal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator ==(Rgb left, Rgb right) => left.Equals(right); /// @@ -144,14 +144,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgb left, Rgb right) => !left.Equals(right); /// /// Returns a new representing this instance. /// /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector3 ToVector3() => new Vector3(this.R, this.G, this.B); /// @@ -165,16 +165,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "Rgb [ Empty ]" - : $"Rgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; + return $"Rgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; } /// public override bool Equals(object obj) => obj is Rgb other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(Rgb other) { return this.R.Equals(other.R) diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index 88f7cac4c3..0d426f3c24 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The y luminance component. /// The cb chroma component. /// The cr chroma component. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public YCbCr(float y, float cb, float cr) : this(new Vector3(y, cb, cr)) { @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Initializes a new instance of the struct. /// /// The vector representing the y, cb, cr components. - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public YCbCr(Vector3 vector) { vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); @@ -80,11 +80,11 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// True if the current left is unequal to the parameter; otherwise, false. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(YCbCr left, YCbCr right) => !left.Equals(right); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() { int hash = this.Y.GetHashCode(); @@ -95,16 +95,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public override string ToString() { - return this.Equals(default) - ? "YCbCr [ Empty ]" - : $"YCbCr [ Y={this.Y}, Cb={this.Cb}, Cr={this.Cr} ]"; + return $"YCbCr [ Y={this.Y}, Cb={this.Cb}, Cr={this.Cr} ]"; } /// public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public bool Equals(YCbCr other) { return this.Y.Equals(other.Y) From 0a5c84adbdedfa3b4d5a78776af82fa2a9ca936c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 29 Jul 2018 22:58:16 +0100 Subject: [PATCH 024/185] Make ColorSpaceConverter immutable. --- .../Conversion/ColorSpaceConverter.Adapt.cs | 37 ++++--- .../Conversion/ColorSpaceConverter.CieLab.cs | 8 +- .../Conversion/ColorSpaceConverter.CieLch.cs | 2 +- .../ColorSpaceConverter.CieLchuv.cs | 7 +- .../Conversion/ColorSpaceConverter.CieLuv.cs | 8 +- .../Conversion/ColorSpaceConverter.CieXyz.cs | 10 +- .../ColorSpaceConverter.HunterLab.cs | 6 +- .../ColorSpaceConverter.LinearRgb.cs | 6 +- .../Conversion/ColorSpaceConverter.Lms.cs | 2 +- .../Conversion/ColorSpaceConverter.cs | 98 +++++-------------- .../Conversion/ColorSpaceConverterOptions.cs | 55 +++++++++++ .../Implementation/CieXyzAndLmsConverter.cs | 20 +--- .../Color/RgbWorkingSpaceAdapt.cs | 2 +- .../Colorspaces/ColorSpaceEqualityTests.cs | 4 + .../CieXyzAndCieLabConversionTest.cs | 6 +- .../CieXyzAndCieLuvConversionTest.cs | 6 +- .../CieXyzAndHunterLabConversionTest.cs | 9 +- .../Conversion/ColorConverterAdaptTest.cs | 20 ++-- .../Conversion/RgbAndCieXyzConversionTest.cs | 12 ++- 19 files changed, 165 insertions(+), 153 deletions(-) create mode 100644 src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index 055e9fbfc7..29d4fca5e4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -14,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// /// Performs chromatic adaptation of given color. - /// Target white point is . + /// Target white point is . /// /// The color to adapt /// The white point to adapt for @@ -22,11 +21,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint) { this.CheckChromaticAdaptation(); - return this.ChromaticAdaptation.Transform(color, sourceWhitePoint, this.WhitePoint); + return this.chromaticAdaptation.Transform(color, sourceWhitePoint, this.whitePoint); } /// - /// Adapts color from the source white point to white point set in . + /// Adapts color from the source white point to white point set in . /// /// The color to adapt /// The adapted color @@ -34,7 +33,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { this.CheckChromaticAdaptation(); - if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) + if (color.WhitePoint.Equals(this.targetLabWhitePoint)) { return color; } @@ -44,7 +43,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - /// Adapts color from the source white point to white point set in . + /// Adapts color from the source white point to white point set in . /// /// The color to adapt /// The adapted color @@ -52,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { this.CheckChromaticAdaptation(); - if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) + if (color.WhitePoint.Equals(this.targetLabWhitePoint)) { return color; } @@ -62,7 +61,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - /// Adapts color from the source white point to white point set in . + /// Adapts color from the source white point to white point set in . /// /// The color to adapt /// The adapted color @@ -70,7 +69,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { this.CheckChromaticAdaptation(); - if (color.WhitePoint.Equals(this.TargetLabWhitePoint)) + if (color.WhitePoint.Equals(this.targetLabWhitePoint)) { return color; } @@ -80,7 +79,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - /// Adapts color from the source white point to white point set in . + /// Adapts color from the source white point to white point set in . /// /// The color to adapt /// The adapted color @@ -88,7 +87,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { this.CheckChromaticAdaptation(); - if (color.WhitePoint.Equals(this.TargetLuvWhitePoint)) + if (color.WhitePoint.Equals(this.targetLuvWhitePoint)) { return color; } @@ -98,7 +97,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - /// Adapts color from the source white point to white point set in . + /// Adapts color from the source white point to white point set in . /// /// The color to adapt /// The adapted color @@ -106,7 +105,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { this.CheckChromaticAdaptation(); - if (color.WhitePoint.Equals(this.TargetHunterLabWhitePoint)) + if (color.WhitePoint.Equals(this.targetHunterLabWhitePoint)) { return color; } @@ -116,7 +115,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion } /// - /// Adapts a color from the source working space to working space set in . + /// Adapts a color from the source working space to working space set in . /// /// The color to adapt /// The adapted color @@ -124,7 +123,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { this.CheckChromaticAdaptation(); - if (color.WorkingSpace.Equals(this.TargetRgbWorkingSpace)) + if (color.WorkingSpace.Equals(this.targetRgbWorkingSpace)) { return color; } @@ -134,15 +133,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz unadapted = converterToXYZ.Convert(color); // Adaptation - CieXyz adapted = this.ChromaticAdaptation.Transform(unadapted, color.WorkingSpace.WhitePoint, this.TargetRgbWorkingSpace.WhitePoint); + CieXyz adapted = this.chromaticAdaptation.Transform(unadapted, color.WorkingSpace.WhitePoint, this.targetRgbWorkingSpace.WhitePoint); // Conversion back to RGB - CieXyzToLinearRgbConverter converterToRGB = this.GetCieXyxToLinearRgbConverter(this.TargetRgbWorkingSpace); + CieXyzToLinearRgbConverter converterToRGB = this.GetCieXyxToLinearRgbConverter(this.targetRgbWorkingSpace); return converterToRGB.Convert(adapted); } /// - /// Adapts an color from the source working space to working space set in . + /// Adapts an color from the source working space to working space set in . /// /// The color to adapt /// The adapted color @@ -157,7 +156,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { const string NoAdapterMessage = "Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."; - if (!this.IsChromaticAdaptationPerformed) + if (!this.performChromaticAdaptation) { throw new InvalidOperationException(NoAdapterMessage); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 37f0e8567d..9095d3f59c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -28,7 +28,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion // Conversion (perserving white point) CieLab unadapted = CieLchToCieLabConverter.Convert(color); - if (!this.IsChromaticAdaptationPerformed) + if (!this.performChromaticAdaptation) { return unadapted; } @@ -165,12 +165,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLab ToCieLab(in CieXyz color) { // Adaptation - CieXyz adapted = !this.WhitePoint.Equals(this.TargetLabWhitePoint) && this.IsChromaticAdaptationPerformed - ? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetLabWhitePoint) + CieXyz adapted = !this.whitePoint.Equals(this.targetLabWhitePoint) && this.performChromaticAdaptation + ? this.chromaticAdaptation.Transform(color, this.whitePoint, this.targetLabWhitePoint) : color; // Conversion - var converter = new CieXyzToCieLabConverter(this.TargetLabWhitePoint); + var converter = new CieXyzToCieLabConverter(this.targetLabWhitePoint); return converter.Convert(adapted); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 0f54471e60..b7b29109d8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLch ToCieLch(in CieLab color) { // Adaptation - CieLab adapted = this.IsChromaticAdaptationPerformed ? this.Adapt(color) : color; + CieLab adapted = this.performChromaticAdaptation ? this.Adapt(color) : color; // Conversion return CieLabToCieLchConverter.Convert(adapted); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 77e707621a..1f831984af 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLchuv ToCieLchuv(in CieLuv color) { // Adaptation - CieLuv adapted = this.IsChromaticAdaptationPerformed ? this.Adapt(color) : color; + CieLuv adapted = this.performChromaticAdaptation ? this.Adapt(color) : color; // Conversion return CieLuvToCieLchuvConverter.Convert(adapted); @@ -388,7 +388,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The color to convert. /// The - public CieLchuv ToCieLchuv(Rgb color) + public CieLchuv ToCieLchuv(in Rgb color) { var xyzColor = this.ToCieXyz(color); @@ -423,8 +423,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieLchuv ToCieLchuv(in YCbCr color) { - CieXyz xyzColor = this.ToCieXyz(color); - + var xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index a0dc4ea890..5b41ba51e1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -90,7 +90,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion // Conversion (perserving white point) CieLuv unadapted = CieLchuvToCieLuvConverter.Convert(color); - if (!this.IsChromaticAdaptationPerformed) + if (!this.performChromaticAdaptation) { return unadapted; } @@ -160,12 +160,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLuv ToCieLuv(in CieXyz color) { // Adaptation - CieXyz adapted = !this.WhitePoint.Equals(this.TargetLabWhitePoint) && this.IsChromaticAdaptationPerformed - ? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetLabWhitePoint) + CieXyz adapted = !this.whitePoint.Equals(this.targetLabWhitePoint) && this.performChromaticAdaptation + ? this.chromaticAdaptation.Transform(color, this.whitePoint, this.targetLabWhitePoint) : color; // Conversion - var converter = new CieXyzToCieLuvConverter(this.TargetLuvWhitePoint); + var converter = new CieXyzToCieLuvConverter(this.targetLuvWhitePoint); return converter.Convert(adapted); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index b29e249055..20aa359ca8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz unadapted = CieLabToCieXyzConverter.Convert(color); // Adaptation - CieXyz adapted = color.WhitePoint.Equals(this.WhitePoint) || !this.IsChromaticAdaptationPerformed + CieXyz adapted = color.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation ? unadapted : this.Adapt(unadapted, color.WhitePoint); @@ -141,7 +141,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz unadapted = CieLuvToCieXyzConverter.Convert(color); // Adaptation - CieXyz adapted = color.WhitePoint.Equals(this.WhitePoint) || !this.IsChromaticAdaptationPerformed + CieXyz adapted = color.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation ? unadapted : this.Adapt(unadapted, color.WhitePoint); @@ -314,7 +314,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color); // Adaptation - CieXyz adapted = color.WhitePoint.Equals(this.WhitePoint) || !this.IsChromaticAdaptationPerformed + CieXyz adapted = color.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation ? unadapted : this.Adapt(unadapted, color.WhitePoint); @@ -354,7 +354,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz unadapted = converter.Convert(color); // Adaptation - return color.WorkingSpace.WhitePoint.Equals(this.WhitePoint) || !this.IsChromaticAdaptationPerformed + return color.WorkingSpace.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation ? unadapted : this.Adapt(unadapted, color.WorkingSpace.WhitePoint); } @@ -388,7 +388,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieXyz ToCieXyz(in Lms color) { // Conversion - return this.cachedCieXyzAndLmsConverter.Convert(color); + return this.cieXyzAndLmsConverter.Convert(color); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index a4a9aa24d1..bb3e1e4cee 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -181,12 +181,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public HunterLab ToHunterLab(in CieXyz color) { // Adaptation - CieXyz adapted = !this.WhitePoint.Equals(this.TargetHunterLabWhitePoint) && this.IsChromaticAdaptationPerformed - ? this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetHunterLabWhitePoint) + CieXyz adapted = !this.whitePoint.Equals(this.targetHunterLabWhitePoint) && this.performChromaticAdaptation + ? this.chromaticAdaptation.Transform(color, this.whitePoint, this.targetHunterLabWhitePoint) : color; // Conversion - return new CieXyzToHunterLabConverter(this.TargetHunterLabWhitePoint).Convert(adapted); + return new CieXyzToHunterLabConverter(this.targetHunterLabWhitePoint).Convert(adapted); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index f4a628cb8c..f95350b298 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -185,12 +185,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public LinearRgb ToLinearRgb(in CieXyz color) { // Adaptation - CieXyz adapted = this.TargetRgbWorkingSpace.WhitePoint.Equals(this.WhitePoint) || !this.IsChromaticAdaptationPerformed + CieXyz adapted = this.targetRgbWorkingSpace.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation ? color - : this.ChromaticAdaptation.Transform(color, this.WhitePoint, this.TargetRgbWorkingSpace.WhitePoint); + : this.chromaticAdaptation.Transform(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); // Conversion - CieXyzToLinearRgbConverter xyzConverter = this.GetCieXyxToLinearRgbConverter(this.TargetRgbWorkingSpace); + CieXyzToLinearRgbConverter xyzConverter = this.GetCieXyxToLinearRgbConverter(this.targetRgbWorkingSpace); return xyzConverter.Convert(adapted); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index a328057ac2..840a994144 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -179,7 +179,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public Lms ToLms(in CieXyz color) { - return this.cachedCieXyzAndLmsConverter.Convert(color); + return this.cieXyzAndLmsConverter.Convert(color); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index 7de590e225..e26ef8da11 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -7,94 +7,46 @@ using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// - /// Converts between color spaces ensuring that the color is adapted using chromatic adaptation. + /// Provides methods to allow the conversion of color values into different color spaces. /// public partial class ColorSpaceConverter { - /// - /// The default whitepoint used for converting to CieLab - /// - public static readonly CieXyz DefaultWhitePoint = Illuminants.D65; + // Options. + private CieXyz whitePoint; + private CieXyz targetLuvWhitePoint; + private CieXyz targetLabWhitePoint; + private CieXyz targetHunterLabWhitePoint; + private RgbWorkingSpace targetRgbWorkingSpace; + private IChromaticAdaptation chromaticAdaptation; + private bool performChromaticAdaptation; + private Matrix4x4 lmsAdaptationMatrix; - private Matrix4x4 transformationMatrix; - - private CieXyzAndLmsConverter cachedCieXyzAndLmsConverter; + private CieXyzAndLmsConverter cieXyzAndLmsConverter; /// /// Initializes a new instance of the class. /// public ColorSpaceConverter() + : this(new ColorSpaceConverterOptions()) { - // Note the order here this is important. - this.WhitePoint = DefaultWhitePoint; - this.LmsAdaptationMatrix = CieXyzAndLmsConverter.DefaultTransformationMatrix; - this.ChromaticAdaptation = new VonKriesChromaticAdaptation(this.cachedCieXyzAndLmsConverter); - this.TargetLuvWhitePoint = CieLuv.DefaultWhitePoint; - this.TargetLabWhitePoint = CieLab.DefaultWhitePoint; - this.TargetHunterLabWhitePoint = HunterLab.DefaultWhitePoint; - this.TargetRgbWorkingSpace = Rgb.DefaultWorkingSpace; } /// - /// Gets or sets the white point used for chromatic adaptation in conversions from/to XYZ color space. - /// When null, no adaptation will be performed. - /// - public CieXyz WhitePoint { get; set; } - - /// - /// Gets or sets the white point used *when creating* Luv/LChuv colors. (Luv/LChuv colors on the input already contain the white point information) - /// Defaults to: . - /// - public CieXyz TargetLuvWhitePoint { get; set; } - - /// - /// Gets or sets the white point used *when creating* Lab/LChab colors. (Lab/LChab colors on the input already contain the white point information) - /// Defaults to: . - /// - public CieXyz TargetLabWhitePoint { get; set; } - - /// - /// Gets or sets the white point used *when creating* HunterLab colors. (HunterLab colors on the input already contain the white point information) - /// Defaults to: . - /// - public CieXyz TargetHunterLabWhitePoint { get; set; } - - /// - /// Gets or sets the target working space used *when creating* RGB colors. (RGB colors on the input already contain the working space information) - /// Defaults to: . - /// - public RgbWorkingSpace TargetRgbWorkingSpace { get; set; } - - /// - /// Gets or sets the chromatic adaptation method used. When null, no adaptation will be performed. - /// - public IChromaticAdaptation ChromaticAdaptation { get; set; } - - /// - /// Gets or sets transformation matrix used in conversion to , - /// also used in the default Von Kries Chromatic Adaptation method. + /// Initializes a new instance of the class. /// - public Matrix4x4 LmsAdaptationMatrix + /// The configuration options. + public ColorSpaceConverter(ColorSpaceConverterOptions options) { - get => this.transformationMatrix; - - set - { - this.transformationMatrix = value; - if (this.cachedCieXyzAndLmsConverter == null) - { - this.cachedCieXyzAndLmsConverter = new CieXyzAndLmsConverter(value); - } - else - { - this.cachedCieXyzAndLmsConverter.TransformationMatrix = value; - } - } + Guard.NotNull(options, nameof(options)); + this.whitePoint = options.WhitePoint; + this.targetLuvWhitePoint = options.TargetLuvWhitePoint; + this.targetLabWhitePoint = options.TargetLabWhitePoint; + this.targetHunterLabWhitePoint = options.TargetHunterLabWhitePoint; + this.targetRgbWorkingSpace = options.TargetRgbWorkingSpace; + this.chromaticAdaptation = options.ChromaticAdaptation; + this.performChromaticAdaptation = this.chromaticAdaptation != null; + this.lmsAdaptationMatrix = options.LmsAdaptationMatrix; + this.cieXyzAndLmsConverter = new CieXyzAndLmsConverter(this.lmsAdaptationMatrix); } - - /// - /// Gets a value indicating whether chromatic adaptation has been performed. - /// - private bool IsChromaticAdaptationPerformed => this.ChromaticAdaptation != null; } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs new file mode 100644 index 0000000000..65fe799949 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs @@ -0,0 +1,55 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion +{ + /// + /// Configuration options for the class. + /// + public class ColorSpaceConverterOptions + { + /// + /// Gets or sets the white point used for chromatic adaptation in conversions from/to XYZ color space. + /// When default, no adaptation will be performed. + /// Defaults to: . + /// + public CieXyz WhitePoint { get; set; } = CieLuv.DefaultWhitePoint; + + /// + /// Gets or sets the white point used *when creating* Luv/LChuv colors. (Luv/LChuv colors on the input already contain the white point information) + /// Defaults to: . + /// + public CieXyz TargetLuvWhitePoint { get; set; } = CieLuv.DefaultWhitePoint; + + /// + /// Gets or sets the white point used *when creating* Lab/LChab colors. (Lab/LChab colors on the input already contain the white point information) + /// Defaults to: . + /// + public CieXyz TargetLabWhitePoint { get; set; } = CieLab.DefaultWhitePoint; + + /// + /// Gets or sets the white point used *when creating* HunterLab colors. (HunterLab colors on the input already contain the white point information) + /// Defaults to: . + /// + public CieXyz TargetHunterLabWhitePoint { get; set; } = HunterLab.DefaultWhitePoint; + + /// + /// Gets or sets the target working space used *when creating* RGB colors. (RGB colors on the input already contain the working space information) + /// Defaults to: . + /// + public RgbWorkingSpace TargetRgbWorkingSpace { get; set; } = Rgb.DefaultWorkingSpace; + + /// + /// Gets or sets the chromatic adaptation method used. When null, no adaptation will be performed. + /// + public IChromaticAdaptation ChromaticAdaptation { get; set; } = new VonKriesChromaticAdaptation(); + + /// + /// Gets or sets transformation matrix used in conversion to and from . + /// + public Matrix4x4 LmsAdaptationMatrix { get; set; } = CieXyzAndLmsConverter.DefaultTransformationMatrix; + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs index 405ccc8194..3bbf1e84aa 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs @@ -39,24 +39,8 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzAndLmsConverter(Matrix4x4 transformationMatrix) { - this.TransformationMatrix = transformationMatrix; - } - - /// - /// Gets or sets the transformation matrix used for the conversion (definition of the cone response domain). - /// - /// - public Matrix4x4 TransformationMatrix - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => this.transformationMatrix; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - set - { - this.transformationMatrix = value; - Matrix4x4.Invert(this.transformationMatrix, out this.inverseTransformationMatrix); - } + this.transformationMatrix = transformationMatrix; + Matrix4x4.Invert(this.transformationMatrix, out this.inverseTransformationMatrix); } /// diff --git a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs index eba6b5d9be..92008f6e20 100644 --- a/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs +++ b/tests/ImageSharp.Benchmarks/Color/RgbWorkingSpaceAdapt.cs @@ -14,7 +14,7 @@ private static readonly RGBColor RGBColor = new RGBColor(0.206162, 0.260277, 0.746717, RGBWorkingSpaces.WideGamutRGB); - private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter { TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + private static readonly ColorSpaceConverter ColorSpaceConverter = new ColorSpaceConverter(new ColorSpaceConverterOptions { TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }); private static readonly ColourfulConverter ColourfulConverter = new ColourfulConverter { TargetRGBWorkingSpace = RGBWorkingSpaces.sRGB }; diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs index 1e629b4553..ba0f11eea8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs @@ -17,6 +17,10 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { var x = default(CieLab); var y = new CieLab(Vector3.One); + + Assert.True(default(CieLab) == default(CieLab)); + Assert.True(default(CieLab) != new CieLab(1, 0, 1)); + Assert.False(default(CieLab) == new CieLab(1, 0, 1)); Assert.Equal(default(CieLab), default(CieLab)); Assert.Equal(new CieLab(1, 0, 1), new CieLab(1, 0, 1)); Assert.Equal(new CieLab(Vector3.One), new CieLab(Vector3.One)); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs index 66f7e75ada..746e37c0e6 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLabConversionTest.cs @@ -35,7 +35,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new CieLab(l, a, b, Illuminants.D65); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var converter = new ColorSpaceConverter(options); var expected = new CieXyz(x, y, z); Span inputSpan = new CieLab[5]; @@ -70,7 +71,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new CieXyz(x, y, z); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var converter = new ColorSpaceConverter(options); var expected = new CieLab(l, a, b); Span inputSpan = new CieXyz[5]; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs index a6a7ee7aec..c0856a2bc1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLuvConversionTest.cs @@ -34,7 +34,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new CieLuv(l, u, v, Illuminants.D65); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var converter = new ColorSpaceConverter(options); var expected = new CieXyz(x, y, z); Span inputSpan = new CieLuv[5]; @@ -69,7 +70,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new CieXyz(x, y, z); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetLabWhitePoint = Illuminants.D65 }; + var converter = new ColorSpaceConverter(options); var expected = new CieLuv(l, u, v); Span inputSpan = new CieXyz[5]; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs index 2251777927..d162940151 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHunterLabConversionTest.cs @@ -29,7 +29,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new HunterLab(l, a, b); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.C }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.C }; + var converter = new ColorSpaceConverter(options); var expected = new CieXyz(x, y, z); Span inputSpan = new HunterLab[5]; @@ -60,7 +61,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new HunterLab(l, a, b); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65 }; + var converter = new ColorSpaceConverter(options); var expected = new CieXyz(x, y, z); Span inputSpan = new HunterLab[5]; @@ -91,7 +93,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new CieXyz(x, y, z); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65 }; + var converter = new ColorSpaceConverter(options); var expected = new HunterLab(l, a, b); Span inputSpan = new CieXyz[5]; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs index f5dc6f6118..af9b8c5b33 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs @@ -27,7 +27,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Arrange var input = new Rgb(r1, g1, b1, RgbWorkingSpaces.WideGamutRgb); var expected = new Rgb(r2, g2, b2, RgbWorkingSpaces.SRgb); - var converter = new ColorSpaceConverter { TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + var options = new ColorSpaceConverterOptions { TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + var converter = new ColorSpaceConverter(options); // Action Rgb actual = converter.Adapt(input); @@ -46,7 +47,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Arrange var input = new Rgb(r1, g1, b1, RgbWorkingSpaces.SRgb); var expected = new Rgb(r2, g2, b2, RgbWorkingSpaces.WideGamutRgb); - var converter = new ColorSpaceConverter { TargetRgbWorkingSpace = RgbWorkingSpaces.WideGamutRgb }; + var options = new ColorSpaceConverterOptions { TargetRgbWorkingSpace = RgbWorkingSpaces.WideGamutRgb }; + var converter = new ColorSpaceConverter(options); // Action Rgb actual = converter.Adapt(input); @@ -64,7 +66,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Arrange var input = new CieLab(l1, a1, b1, Illuminants.D65); var expected = new CieLab(l2, a2, b2); - var converter = new ColorSpaceConverter { TargetLabWhitePoint = Illuminants.D50 }; + var options = new ColorSpaceConverterOptions { TargetLabWhitePoint = Illuminants.D50 }; + var converter = new ColorSpaceConverter(options); // Action CieLab actual = converter.Adapt(input); @@ -81,7 +84,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Arrange var input = new CieXyz(x1, y1, z1); var expected = new CieXyz(x2, y2, z2); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D50 }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D50 }; + var converter = new ColorSpaceConverter(options); // Action CieXyz actual = converter.Adapt(input, Illuminants.D65); @@ -98,12 +102,14 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Arrange var input = new CieXyz(x1, y1, z1); var expected = new CieXyz(x2, y2, z2); - var converter = new ColorSpaceConverter + var options = new ColorSpaceConverterOptions { ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), WhitePoint = Illuminants.D50 }; + var converter = new ColorSpaceConverter(options); + // Action CieXyz actual = converter.Adapt(input, Illuminants.D65); @@ -119,12 +125,14 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion // Arrange var input = new CieXyz(x1, y1, z1); var expected = new CieXyz(x2, y2, z2); - var converter = new ColorSpaceConverter + var options = new ColorSpaceConverterOptions { ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), WhitePoint = Illuminants.D50 }; + var converter = new ColorSpaceConverter(options); + // Action CieXyz actual = converter.Adapt(input, Illuminants.D65); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs index ea1d0db00f..a3b0cbd953 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/RgbAndCieXyzConversionTest.cs @@ -34,7 +34,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new CieXyz(x, y, z); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D50, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D50, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + var converter = new ColorSpaceConverter(options); var expected = new Rgb(r, g, b); Span inputSpan = new CieXyz[5]; @@ -72,7 +73,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new CieXyz(x, y, z); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65, TargetRgbWorkingSpace = RgbWorkingSpaces.SRgb }; + var converter = new ColorSpaceConverter(options); var expected = new Rgb(r, g, b); Span inputSpan = new CieXyz[5]; @@ -109,7 +111,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new Rgb(r, g, b); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D50 }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D50 }; + var converter = new ColorSpaceConverter(options); var expected = new CieXyz(x, y, z); Span inputSpan = new Rgb[5]; @@ -145,7 +148,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { // Arrange var input = new Rgb(r, g, b); - var converter = new ColorSpaceConverter { WhitePoint = Illuminants.D65 }; + var options = new ColorSpaceConverterOptions { WhitePoint = Illuminants.D65 }; + var converter = new ColorSpaceConverter(options); var expected = new CieXyz(x, y, z); Span inputSpan = new Rgb[5]; From b97ecb0dcf2fe1335a74b251e9d9cca308568a78 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 Jul 2018 14:25:39 +0100 Subject: [PATCH 025/185] Remove per-pixel allocation --- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs | 3 +-- src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs | 5 ++++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 9095d3f59c..099a103a7d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -170,8 +170,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion : color; // Conversion - var converter = new CieXyzToCieLabConverter(this.targetLabWhitePoint); - return converter.Convert(adapted); + return this.cieXyzToCieLabConverter.Convert(adapted); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index e26ef8da11..e092d2d650 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// - /// Provides methods to allow the conversion of color values into different color spaces. + /// Provides methods to allow the conversion of color values between different color spaces. /// public partial class ColorSpaceConverter { @@ -22,6 +22,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion private Matrix4x4 lmsAdaptationMatrix; private CieXyzAndLmsConverter cieXyzAndLmsConverter; + private CieXyzToCieLabConverter cieXyzToCieLabConverter; /// /// Initializes a new instance of the class. @@ -46,7 +47,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion this.chromaticAdaptation = options.ChromaticAdaptation; this.performChromaticAdaptation = this.chromaticAdaptation != null; this.lmsAdaptationMatrix = options.LmsAdaptationMatrix; + this.cieXyzAndLmsConverter = new CieXyzAndLmsConverter(this.lmsAdaptationMatrix); + this.cieXyzToCieLabConverter = new CieXyzToCieLabConverter(this.targetLabWhitePoint); } } } \ No newline at end of file From 6683287d95e8a3c2c4ef7eaf67d0b5e00c42024f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 Jul 2018 14:25:48 +0100 Subject: [PATCH 026/185] Notes --- .../ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs | 2 +- src/ImageSharp/PixelFormats/README.md | 4 ---- 2 files changed, 1 insertion(+), 5 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs index d2ba91ce28..2b8672f27a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public bool Equals(RgbWorkingSpace other) { - // TODO: Object.Equals for ICompanding will be slow. + // Object.Equals for ICompanding compares the reference only. return this.WhitePoint.Equals(other.WhitePoint) && this.ChromaticityCoordinates.Equals(other.ChromaticityCoordinates) && Equals(this.Companding, other.Companding); diff --git a/src/ImageSharp/PixelFormats/README.md b/src/ImageSharp/PixelFormats/README.md index c332bc92c1..cbebaf23ad 100644 --- a/src/ImageSharp/PixelFormats/README.md +++ b/src/ImageSharp/PixelFormats/README.md @@ -2,9 +2,5 @@ https://github.com/MonoGame/MonoGame -Rgba32 is our default format. As such it positioned within the ImageSharp root namespace to ensure visibility of the format. - -All other pixel formats should be positioned within ImageSharp.PixelFormats to reduce intellisense burden. - The naming convention of each pixel format is to order the color components from least significant to most significant, reading from left to right. For example in the Rgba32 pixel format the R component is the least significant byte, and the A component is the most significant. From 661c0dca6d6cac71ff7d62668856a19f67968edb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 Jul 2018 15:38:46 +0100 Subject: [PATCH 027/185] Remove interface. --- .../Conversion/IColorConversion.cs | 22 ------------------- .../Implementation/CIeLchToCieLabConverter.cs | 8 +++++-- .../Implementation/CieLabToCieLchConverter.cs | 8 +++++-- .../Implementation/CieLabToCieXyzConverter.cs | 9 +++++--- .../CieLchuvToCieLuvConverter.cs | 8 +++++-- .../CieLuvToCieLchuvConverter.cs | 8 +++++-- .../Implementation/CieLuvToCieXyzConverter.cs | 8 +++++-- .../CieXyzAndCieXyyConverter.cs | 14 +++++++++--- .../Implementation/CieXyzAndLmsConverter.cs | 16 ++++++++++---- .../Implementation/CieXyzToCieLabConverter.cs | 8 +++++-- .../Implementation/CieXyzToCieLuvConverter.cs | 8 +++++-- .../CieXyzToHunterLabConverter.cs | 10 ++++++--- .../CieXyzToLinearRgbConverter.cs | 10 ++++++--- .../Implementation/CmykAndRgbConverter.cs | 18 ++++++++++----- .../Implementation/HslAndRgbConverter.cs | 14 +++++++++--- .../Implementation/HsvAndRgbConverter.cs | 14 +++++++++--- .../HunterLabToCieXyzConverter.cs | 10 ++++++--- .../LinearRgbAndCieXyzConverterBase.cs | 2 +- .../LinearRgbToCieXyzConverter.cs | 10 ++++++--- .../Implementation/LinearRgbToRgbConverter.cs | 10 ++++++--- .../Implementation/LmsAdaptationMatrix.cs | 2 +- .../Implementation/RgbToLinearRgbConverter.cs | 10 ++++++--- .../Implementation/YCbCrAndRgbConverter.cs | 16 ++++++++++---- 23 files changed, 162 insertions(+), 81 deletions(-) delete mode 100644 src/ImageSharp/ColorSpaces/Conversion/IColorConversion.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/IColorConversion.cs b/src/ImageSharp/ColorSpaces/Conversion/IColorConversion.cs deleted file mode 100644 index 009b91c40a..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/IColorConversion.cs +++ /dev/null @@ -1,22 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion -{ - /// - /// Converts color between two color spaces. - /// - /// The input color type. - /// The result color type. - internal interface IColorConversion - where T : struct - where TResult : struct - { - /// - /// Performs the conversion from the input to an instance of the output type. - /// - /// The input color instance. - /// The converted result - TResult Convert(in T input); - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs index 05d8ef551c..7a71a1cc44 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs @@ -9,9 +9,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal sealed class CieLchToCieLabConverter : IColorConversion + internal sealed class CieLchToCieLabConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLab Convert(in CieLch input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs index c82ad4ad92..150f198882 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs @@ -9,9 +9,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal sealed class CieLabToCieLchConverter : IColorConversion + internal sealed class CieLabToCieLchConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLch Convert(in CieLab input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs index 88d965b5bb..707300eda2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -10,9 +9,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal sealed class CieLabToCieXyzConverter : IColorConversion + internal sealed class CieLabToCieXyzConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(in CieLab input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs index 3428dd0ae2..c3e85ba735 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs @@ -9,9 +9,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal sealed class CieLchuvToCieLuvConverter : IColorConversion + internal sealed class CieLchuvToCieLuvConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv Convert(in CieLchuv input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs index 9670a704e1..b8e5d6f903 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs @@ -9,9 +9,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal sealed class CieLuvToCieLchuvConverter : IColorConversion + internal sealed class CieLuvToCieLchuvConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLchuv Convert(in CieLuv input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs index 9874a82907..ecd26fdf6d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs @@ -9,9 +9,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal sealed class CieLuvToCieXyzConverter : IColorConversion + internal sealed class CieLuvToCieXyzConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(in CieLuv input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs index 856cd16322..32c1fe4c8e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs @@ -10,9 +10,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Color converter between CIE XYZ and CIE xyY /// for formulas. /// - internal sealed class CieXyzAndCieXyyConverter : IColorConversion, IColorConversion + internal sealed class CieXyzAndCieXyyConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyy Convert(in CieXyz input) { @@ -27,7 +31,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new CieXyy(x, y, input.Y); } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(in CieXyy input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs index 3bbf1e84aa..ed7ccff28c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs @@ -7,9 +7,9 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// Color converter between CIE XYZ and LMS + /// Color converter between and /// - internal sealed class CieXyzAndLmsConverter : IColorConversion, IColorConversion + internal sealed class CieXyzAndLmsConverter { /// /// Default transformation matrix used, when no other is set. (Bradford) @@ -43,7 +43,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation Matrix4x4.Invert(this.transformationMatrix, out this.inverseTransformationMatrix); } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public Lms Convert(in CieXyz input) { @@ -52,7 +56,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new Lms(vector); } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(in Lms input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs index 1e4ad96b0d..54d3e0fecf 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal sealed class CieXyzToCieLabConverter : IColorConversion + internal sealed class CieXyzToCieLabConverter { /// /// Initializes a new instance of the class. @@ -35,7 +35,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public CieXyz LabWhitePoint { get; } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLab Convert(in CieXyz input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs index 614d3973e1..79128e7299 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Converts from to . /// - internal sealed class CieXyzToCieLuvConverter : IColorConversion + internal sealed class CieXyzToCieLuvConverter { /// /// Initializes a new instance of the class. @@ -35,7 +35,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public CieXyz LuvWhitePoint { get; } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv Convert(in CieXyz input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs index d990d3ef6a..31d4332e40 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs @@ -7,9 +7,9 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// Color converter between CieXyz and HunterLab + /// Color converter between and /// - internal sealed class CieXyzToHunterLabConverter : CieXyzAndHunterLabConverterBase, IColorConversion + internal sealed class CieXyzToHunterLabConverter : CieXyzAndHunterLabConverterBase { /// /// Initializes a new instance of the class. @@ -35,7 +35,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public CieXyz HunterLabWhitePoint { get; } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public HunterLab Convert(in CieXyz input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs index a2786654fe..cb3e7d20c8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs @@ -7,9 +7,9 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// Color converter between CieXyz and LinearRgb + /// Color converter between and /// - internal sealed class CieXyzToLinearRgbConverter : LinearRgbAndCieXyzConverterBase, IColorConversion + internal sealed class CieXyzToLinearRgbConverter : LinearRgbAndCieXyzConverterBase { private readonly Matrix4x4 conversionMatrix; @@ -38,7 +38,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public RgbWorkingSpace TargetWorkingSpace { get; } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public LinearRgb Convert(in CieXyz input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs index 6b16e42282..b81c70a1bd 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs @@ -8,11 +8,15 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// Color converter between CMYK and Rgb + /// Color converter between and /// - internal sealed class CmykAndRgbConverter : IColorConversion, IColorConversion + internal sealed class CmykAndRgbConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb Convert(in Cmyk input) { @@ -20,11 +24,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new Rgb(rgb); } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public Cmyk Convert(in Rgb input) { - // To CMYK + // To CMY Vector3 cmy = Vector3.One - input.ToVector3(); // To CMYK diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs index 1a885d6be5..eca114c7b0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs @@ -10,9 +10,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Color converter between HSL and Rgb /// See for formulas. /// - internal sealed class HslAndRgbConverter : IColorConversion, IColorConversion + internal sealed class HslAndRgbConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb Convert(in Hsl input) { @@ -43,7 +47,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new Rgb(r, g, b); } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hsl Convert(in Rgb input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs index ed7c6dd2ca..79bfe73311 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs @@ -10,9 +10,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Color converter between HSV and Rgb /// See for formulas. /// - internal sealed class HsvAndRgbConverter : IColorConversion, IColorConversion + internal sealed class HsvAndRgbConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb Convert(in Hsv input) { @@ -75,7 +79,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new Rgb(r, g, b); } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public Hsv Convert(in Rgb input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs index a7ba26270c..7d71c48a08 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs @@ -7,11 +7,15 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// Color converter between HunterLab and CieXyz + /// Color converter between and /// - internal sealed class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase, IColorConversion + internal sealed class HunterLabToCieXyzConverter : CieXyzAndHunterLabConverterBase { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(in HunterLab input) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs index a9d8e83983..18b3df0d05 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs @@ -6,7 +6,7 @@ using System.Numerics; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// Provides base methods for converting between Rgb and CieXyz color spaces. + /// Provides base methods for converting between and color spaces. /// internal abstract class LinearRgbAndCieXyzConverterBase { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs index 80849021f0..1108f682f5 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs @@ -6,9 +6,9 @@ using System.Numerics; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// Color converter between LinearRgb and CieXyz + /// Color converter between and /// - internal sealed class LinearRgbToCieXyzConverter : LinearRgbAndCieXyzConverterBase, IColorConversion + internal sealed class LinearRgbToCieXyzConverter : LinearRgbAndCieXyzConverterBase { private readonly Matrix4x4 conversionMatrix; @@ -35,7 +35,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// public RgbWorkingSpace SourceWorkingSpace { get; } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result public CieXyz Convert(in LinearRgb input) { DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs index a38a45cb1c..1418f96d71 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs @@ -6,11 +6,15 @@ using System.Numerics; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// Color converter between LinearRgb and Rgb + /// Color converter between and /// - internal sealed class LinearRgbToRgbConverter : IColorConversion + internal sealed class LinearRgbToRgbConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result public Rgb Convert(in LinearRgb input) { var vector = input.ToVector3(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs index aef0b560e5..452cafe794 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs @@ -7,7 +7,7 @@ using System.Numerics; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// AdaptionMatrix3X3 used for transformation from XYZ to LMS, defining the cone response domain. + /// Matrices used for transformation from to , defining the cone response domain. /// Used in /// /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs index c8d04c54ac..d3399d1d59 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs @@ -8,12 +8,16 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Color converter between Rgb and LinearRgb /// - internal class RgbToLinearRgbConverter : IColorConversion + internal class RgbToLinearRgbConverter { - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result public LinearRgb Convert(in Rgb input) { - Vector3 vector = input.ToVector3(); + var vector = input.ToVector3(); vector.X = input.WorkingSpace.Companding.Expand(vector.X); vector.Y = input.WorkingSpace.Companding.Expand(vector.Y); vector.Z = input.WorkingSpace.Companding.Expand(vector.Z); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs index cb7071adf1..a2484ec0b4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs @@ -8,14 +8,18 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// - /// Color converter between YCbCr and Rgb + /// Color converter between and /// See for formulas. /// - internal sealed class YCbCrAndRgbConverter : IColorConversion, IColorConversion + internal sealed class YCbCrAndRgbConverter { private static readonly Vector3 MaxBytes = new Vector3(255F); - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgb Convert(in YCbCr input) { @@ -30,7 +34,11 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation return new Rgb(new Vector3(r, g, b) / MaxBytes); } - /// + /// + /// Performs the conversion from the input to an instance of type. + /// + /// The input color instance. + /// The converted result [MethodImpl(MethodImplOptions.AggressiveInlining)] public YCbCr Convert(in Rgb input) { From bd3cd931d8652b66dea18b828fc4d14d524b76c1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 30 Jul 2018 16:13:44 +0100 Subject: [PATCH 028/185] Add Rgb specific tests --- src/ImageSharp/ColorSpaces/Rgb.cs | 2 +- src/ImageSharp/PixelFormats/Rgba32.cs | 8 +- .../Colorspaces/ColorSpaceEqualityTests.cs | 11 --- .../ImageSharp.Tests/Colorspaces/RgbTests.cs | 86 +++++++++++++++++++ 4 files changed, 89 insertions(+), 18 deletions(-) create mode 100644 tests/ImageSharp.Tests/Colorspaces/RgbTests.cs diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index db2c8e86b5..91a6b23d47 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public static implicit operator Rgb(Rgba32 color) { - return new Rgba32(color.R / 255F, color.G / 255F, color.B / 255F); + return new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); } /// diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index e38368e620..3c94678aaa 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -224,12 +224,8 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Compares two objects for equality. /// - /// - /// The on the left side of the operand. - /// - /// - /// The on the right side of the operand. - /// + /// The on the left side of the operand. + /// The on the right side of the operand. /// /// True if the parameter is equal to the parameter; otherwise, false. /// diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs index ba0f11eea8..df3e0ebfbd 100644 --- a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs @@ -137,17 +137,6 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces Assert.False(x.Equals(y)); } - [Fact] - public void RgbEquality() - { - var x = default(Rgb); - var y = new Rgb(Vector3.One); - Assert.Equal(default(Rgb), default(Rgb)); - Assert.Equal(new Rgb(1, 0, 1), new Rgb(1, 0, 1)); - Assert.Equal(new Rgb(Vector3.One), new Rgb(Vector3.One)); - Assert.False(x.Equals(y)); - } - [Fact] public void YCbCrEquality() { diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs b/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs new file mode 100644 index 0000000000..26352a6147 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs @@ -0,0 +1,86 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.PixelFormats; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + + /// + /// Tests the struct. + /// + public class RgbTests + { + [Fact] + public void RgbConstructorAssignsFields() + { + const float r = .75F; + const float g = .64F; + const float b = .87F; + var rgb = new Rgb(r, g, b); + + Assert.Equal(r, rgb.R); + Assert.Equal(g, rgb.G); + Assert.Equal(b, rgb.B); + } + + [Fact] + public void RgbEquality() + { + var x = default(Rgb); + var y = new Rgb(Vector3.One); + + Assert.True(default(Rgb) == default(Rgb)); + Assert.False(default(Rgb) != default(Rgb)); + Assert.Equal(default(Rgb), default(Rgb)); + Assert.Equal(new Rgb(1, 0, 1), new Rgb(1, 0, 1)); + Assert.Equal(new Rgb(Vector3.One), new Rgb(Vector3.One)); + Assert.False(x.Equals(y)); + } + + [Fact] + public void RgbAndRgb24Operators() + { + const byte r = 64; + const byte g = 128; + const byte b = 255; + + var rgb = new Rgb(r / 255F, g / 255F, b / 255F); + + Rgb24 rgb24 = rgb; + Rgb rgb2 = rgb24; + + Assert.Equal(r, rgb24.R); + Assert.Equal(g, rgb24.G); + Assert.Equal(b, rgb24.B); + + Assert.Equal(r / 255F, rgb2.R); + Assert.Equal(g / 255F, rgb2.G); + Assert.Equal(b / 255F, rgb2.B); + } + + [Fact] + public void RgbAndRgba32Operators() + { + const byte r = 64; + const byte g = 128; + const byte b = 255; + + var rgb = new Rgb(r / 255F, g / 255F, b / 255F); + + Rgba32 rgba32 = rgb; + Rgb rgb2 = rgba32; + + Assert.Equal(r, rgba32.R); + Assert.Equal(g, rgba32.G); + Assert.Equal(b, rgba32.B); + + Assert.Equal(r / 255F, rgb2.R); + Assert.Equal(g / 255F, rgb2.G); + Assert.Equal(b / 255F, rgb2.B); + } + } +} From 0427d8c92d8a49c949ef94f3887574f473c673c5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 1 Aug 2018 08:36:12 +0100 Subject: [PATCH 029/185] Calculate bool once in constructor. --- .../ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs | 2 +- src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index 099a103a7d..d971ad1331 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLab ToCieLab(in CieXyz color) { // Adaptation - CieXyz adapted = !this.whitePoint.Equals(this.targetLabWhitePoint) && this.performChromaticAdaptation + CieXyz adapted = this.performLabChromaticAdaptation ? this.chromaticAdaptation.Transform(color, this.whitePoint, this.targetLabWhitePoint) : color; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index e092d2d650..bf28780dc4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -19,6 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion private RgbWorkingSpace targetRgbWorkingSpace; private IChromaticAdaptation chromaticAdaptation; private bool performChromaticAdaptation; + private bool performLabChromaticAdaptation; private Matrix4x4 lmsAdaptationMatrix; private CieXyzAndLmsConverter cieXyzAndLmsConverter; @@ -46,6 +47,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion this.targetRgbWorkingSpace = options.TargetRgbWorkingSpace; this.chromaticAdaptation = options.ChromaticAdaptation; this.performChromaticAdaptation = this.chromaticAdaptation != null; + this.performLabChromaticAdaptation = !this.whitePoint.Equals(this.targetLabWhitePoint) && this.performChromaticAdaptation; this.lmsAdaptationMatrix = options.LmsAdaptationMatrix; this.cieXyzAndLmsConverter = new CieXyzAndLmsConverter(this.lmsAdaptationMatrix); From 6efeafb663eb03beb86ff13e24a1ae2e7ee170ab Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 5 Aug 2018 17:42:17 +0200 Subject: [PATCH 030/185] use ImageSharp Guard / DebugGuard --- src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs | 2 +- src/ImageSharp/Memory/BasicArrayBuffer.cs | 2 +- src/ImageSharp/Memory/Buffer2D{T}.cs | 2 +- src/ImageSharp/Memory/BufferArea{T}.cs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs b/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs index 32c1c6d1d8..f1921d2a0a 100644 --- a/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs +++ b/src/ImageSharp/Memory/ArrayPoolMemoryAllocator.cs @@ -62,7 +62,7 @@ namespace SixLabors.Memory public ArrayPoolMemoryAllocator(int maxPoolSizeInBytes, int poolSelectorThresholdInBytes, int maxArraysPerBucketLargePool, int maxArraysPerBucketNormalPool) { ImageSharp.Guard.MustBeGreaterThan(maxPoolSizeInBytes, 0, nameof(maxPoolSizeInBytes)); - Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes)); + ImageSharp.Guard.MustBeLessThanOrEqualTo(poolSelectorThresholdInBytes, maxPoolSizeInBytes, nameof(poolSelectorThresholdInBytes)); this.MaxPoolSizeInBytes = maxPoolSizeInBytes; this.PoolSelectorThresholdInBytes = poolSelectorThresholdInBytes; diff --git a/src/ImageSharp/Memory/BasicArrayBuffer.cs b/src/ImageSharp/Memory/BasicArrayBuffer.cs index f40df76049..6cbaa0364c 100644 --- a/src/ImageSharp/Memory/BasicArrayBuffer.cs +++ b/src/ImageSharp/Memory/BasicArrayBuffer.cs @@ -38,7 +38,7 @@ namespace SixLabors.Memory [MethodImpl(MethodImplOptions.AggressiveInlining)] get { - DebugGuard.MustBeLessThan(index, this.Length, nameof(index)); + ImageSharp.DebugGuard.MustBeLessThan(index, this.Length, nameof(index)); Span span = this.GetSpan(); return ref span[index]; diff --git a/src/ImageSharp/Memory/Buffer2D{T}.cs b/src/ImageSharp/Memory/Buffer2D{T}.cs index 844ca1ad10..1e05fef6d1 100644 --- a/src/ImageSharp/Memory/Buffer2D{T}.cs +++ b/src/ImageSharp/Memory/Buffer2D{T}.cs @@ -62,7 +62,7 @@ namespace SixLabors.Memory get { ImageSharp.DebugGuard.MustBeLessThan(x, this.Width, nameof(x)); - DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); + ImageSharp.DebugGuard.MustBeLessThan(y, this.Height, nameof(y)); Span span = this.Span; return ref span[(this.Width * y) + x]; } diff --git a/src/ImageSharp/Memory/BufferArea{T}.cs b/src/ImageSharp/Memory/BufferArea{T}.cs index 6a2146fd20..d8e588dcfe 100644 --- a/src/ImageSharp/Memory/BufferArea{T}.cs +++ b/src/ImageSharp/Memory/BufferArea{T}.cs @@ -120,7 +120,7 @@ namespace SixLabors.Memory public BufferArea GetSubArea(Rectangle rectangle) { ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Width, this.Rectangle.Width, nameof(rectangle)); - DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, this.Rectangle.Height, nameof(rectangle)); + ImageSharp.DebugGuard.MustBeLessThanOrEqualTo(rectangle.Height, this.Rectangle.Height, nameof(rectangle)); int x = this.Rectangle.X + rectangle.X; int y = this.Rectangle.Y + rectangle.Y; From 4a791cc516a5166ad6e8e32267daa3974327d9f4 Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Mon, 27 Aug 2018 23:05:38 +0200 Subject: [PATCH 031/185] Refactored PixelBlenders so it generates much less code and allows for two loop variations. Generalised DrawingImage methods to support drawing images with a format different than the destination image at no cost. --- .../Processing/DrawImageExtensions.cs | 96 +- .../Processors/Drawing/DrawImageProcessor.cs | 53 +- .../DefaultPixelBlenders.Generated.cs | 3476 +++++++---------- .../DefaultPixelBlenders.Generated.tt | 39 +- .../PixelFormats/PixelBlender{TPixel}.cs | 136 +- 5 files changed, 1641 insertions(+), 2159 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs b/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs index 8ccbe22acb..d236ec35c6 100644 --- a/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs @@ -15,107 +15,123 @@ namespace SixLabors.ImageSharp.Processing /// /// Draws the given image together with the current one by blending their pixels. /// - /// The pixel format. + /// The pixel format of the destination image. + /// The pixel format of the source image. /// The image this method extends. /// The image to blend with the currently processing image. /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, float opacity) - where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity)); + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, float opacity) + where TPixelDst : struct, IPixel + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity)); /// /// Draws the given image together with the current one by blending their pixels. /// - /// The pixel format. + /// The pixel format of the destination image. + /// The pixel format of the source image. /// The image this method extends. /// The image to blend with the currently processing image. /// The blending mode. /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, float opacity) - where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity)); + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, float opacity) + where TPixelDst : struct, IPixel + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity)); /// /// Draws the given image together with the current one by blending their pixels. /// - /// The pixel format. + /// The pixel format of the destination image. + /// The pixel format of the source image. /// The image this method extends. /// The image to blend with the currently processing image. /// The color blending mode. /// The alpha composition mode. /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) - where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, colorBlending, alphaComposition, opacity)); + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) + where TPixelDst : struct, IPixel + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, colorBlending, alphaComposition, opacity)); /// /// Draws the given image together with the current one by blending their pixels. /// - /// The pixel format. + /// The pixel format of the destination image. + /// The pixel format of the source image. /// The image this method extends. /// The image to blend with the currently processing image. /// The options, including the blending type and blending amount. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, GraphicsOptions options) - where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage)); + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, GraphicsOptions options) + where TPixelDst : struct, IPixel + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage)); /// /// Draws the given image together with the current one by blending their pixels. /// - /// The pixel format. + /// The pixel format of the destination image. + /// The pixel format of the source image. /// The image this method extends. /// The image to blend with the currently processing image. /// The location to draw the blended image. /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, float opacity) - where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, location, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity)); + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, float opacity) + where TPixelDst : struct, IPixel + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, location, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity)); /// /// Draws the given image together with the current one by blending their pixels. /// - /// The pixel format. + /// The pixel format of the destination image. + /// The pixel format of the source image. /// The image this method extends. /// The image to blend with the currently processing image. /// The location to draw the blended image. /// The color blending to apply. /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, float opacity) - where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, location, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity)); + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, float opacity) + where TPixelDst : struct, IPixel + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, location, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity)); /// /// Draws the given image together with the current one by blending their pixels. /// - /// The pixel format. + /// The pixel format of the destination image. + /// The pixel format of the source image. /// The image this method extends. /// The image to blend with the currently processing image. /// The location to draw the blended image. /// The color blending to apply. /// The alpha composition mode. /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) - where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, location, colorBlending, alphaComposition, opacity)); + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) + where TPixelDst : struct, IPixel + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, location, colorBlending, alphaComposition, opacity)); /// /// Draws the given image together with the current one by blending their pixels. /// - /// The pixel format. + /// The pixel format of the destination image. + /// The pixel format of the source image. /// The image this method extends. /// The image to blend with the currently processing image. /// The location to draw the blended image. /// The options containing the blend mode and opacity. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, GraphicsOptions options) - where TPixel : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, location, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage)); + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, GraphicsOptions options) + where TPixelDst : struct, IPixel + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, location, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage)); } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index 324d25e097..4e6018e07a 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -15,32 +15,34 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing /// /// Combines two images together by blending the pixels. /// - /// The pixel format. - internal class DrawImageProcessor : ImageProcessor - where TPixel : struct, IPixel + /// The pixel format of destination image. + /// The pixel format os source image. + internal class DrawImageProcessor : ImageProcessor + where TPixelDst : struct, IPixel + where TPixelSrc : struct, IPixel { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the class. /// /// The image to blend with the currently processing image. /// The location to draw the blended image. /// The blending mode to use when drawing the image. /// The Alpha blending mode to use when drawing the image. /// The opacity of the image to blend. Must be between 0 and 1. - public DrawImageProcessor(Image image, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity) + public DrawImageProcessor(Image image, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity) { Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); this.Image = image; this.Opacity = opacity; - this.Blender = PixelOperations.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); + this.Blender = PixelOperations.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); this.Location = location; } /// /// Gets the image to blend /// - public Image Image { get; } + public Image Image { get; } /// /// Gets the opacity of the image to blend @@ -50,7 +52,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing /// /// Gets the pixel blender /// - public PixelBlender Blender { get; } + public PixelBlender Blender { get; } /// /// Gets the location to draw the blended image @@ -58,10 +60,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing public Point Location { get; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - Image targetImage = this.Image; - PixelBlender blender = this.Blender; + Image targetImage = this.Image; + PixelBlender blender = this.Blender; int locationY = this.Location.Y; // Align start/end positions. @@ -76,23 +78,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing int width = maxX - minX; - MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; - - using (IMemoryOwner amount = memoryAllocator.Allocate(width)) - { - amount.GetSpan().Fill(this.Opacity); - - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - Span background = source.GetPixelRowSpan(y).Slice(minX, width); - Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); - blender.Blend(memoryAllocator, background, background, foreground, amount.GetSpan()); - }); - } + MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; + + ParallelFor.WithConfiguration( + minY, + maxY, + configuration, + y => + { + Span background = source.GetPixelRowSpan(y).Slice(minX, width); + Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); + blender.Blend(memoryAllocator, background, background, foreground, this.Opacity); + }); } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 9b1e29db81..cc6743d567 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -1,12 +1,19 @@ -// Copyright (c) Six Labors and contributors. + + + + + + + +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // -using System; -using System.Numerics; -using System.Buffers; - -using SixLabors.ImageSharp.Memory; +using System; +using System.Numerics; +using System.Buffers; + +using SixLabors.ImageSharp.Memory; using SixLabors.Memory; namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders @@ -26,6 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders where TPixel : struct, IPixel { + internal class NormalSrc : PixelBlender { /// @@ -40,31 +48,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalSrc(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount[i]); + } } } + internal class MultiplySrc : PixelBlender { /// @@ -79,31 +81,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplySrc(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount[i]); + } } } + internal class AddSrc : PixelBlender { /// @@ -118,31 +114,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddSrc(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount[i]); + } } } + internal class SubtractSrc : PixelBlender { /// @@ -157,31 +147,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractSrc(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount[i]); + } } } + internal class ScreenSrc : PixelBlender { /// @@ -196,31 +180,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenSrc(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount[i]); + } } } + internal class DarkenSrc : PixelBlender { /// @@ -235,31 +213,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenSrc(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount[i]); + } } } + internal class LightenSrc : PixelBlender { /// @@ -274,31 +246,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenSrc(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount[i]); + } } } + internal class OverlaySrc : PixelBlender { /// @@ -313,31 +279,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlaySrc(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount[i]); + } } } + internal class HardLightSrc : PixelBlender { /// @@ -352,31 +312,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightSrc(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount[i]); + } } } + internal class NormalSrcAtop : PixelBlender { /// @@ -391,31 +345,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount[i]); + } } } + internal class MultiplySrcAtop : PixelBlender { /// @@ -430,31 +378,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplySrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount[i]); + } } } + internal class AddSrcAtop : PixelBlender { /// @@ -469,31 +411,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount[i]); + } } } + internal class SubtractSrcAtop : PixelBlender { /// @@ -508,31 +444,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount[i]); + } } } + internal class ScreenSrcAtop : PixelBlender { /// @@ -547,31 +477,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount[i]); + } } } + internal class DarkenSrcAtop : PixelBlender { /// @@ -586,31 +510,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount[i]); + } } } + internal class LightenSrcAtop : PixelBlender { /// @@ -625,31 +543,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount[i]); + } } } + internal class OverlaySrcAtop : PixelBlender { /// @@ -664,31 +576,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlaySrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount[i]); + } } } + internal class HardLightSrcAtop : PixelBlender { /// @@ -703,31 +609,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightSrcAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount[i]); + } } } + internal class NormalSrcOver : PixelBlender { /// @@ -742,31 +642,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount[i]); + } } } + internal class MultiplySrcOver : PixelBlender { /// @@ -781,31 +675,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplySrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount[i]); + } } } + internal class AddSrcOver : PixelBlender { /// @@ -820,31 +708,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount[i]); + } } } + internal class SubtractSrcOver : PixelBlender { /// @@ -859,31 +741,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount[i]); + } } } + internal class ScreenSrcOver : PixelBlender { /// @@ -898,31 +774,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount[i]); + } } } + internal class DarkenSrcOver : PixelBlender { /// @@ -937,31 +807,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount[i]); + } } } + internal class LightenSrcOver : PixelBlender { /// @@ -976,31 +840,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount[i]); + } } } + internal class OverlaySrcOver : PixelBlender { /// @@ -1015,31 +873,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlaySrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount[i]); + } } } + internal class HardLightSrcOver : PixelBlender { /// @@ -1054,31 +906,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightSrcOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount[i]); + } } } + internal class NormalSrcIn : PixelBlender { /// @@ -1093,31 +939,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount[i]); + } } } + internal class MultiplySrcIn : PixelBlender { /// @@ -1132,31 +972,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplySrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount[i]); + } } } + internal class AddSrcIn : PixelBlender { /// @@ -1171,31 +1005,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount[i]); + } } } + internal class SubtractSrcIn : PixelBlender { /// @@ -1210,31 +1038,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount[i]); + } } } + internal class ScreenSrcIn : PixelBlender { /// @@ -1249,31 +1071,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount[i]); + } } } + internal class DarkenSrcIn : PixelBlender { /// @@ -1288,31 +1104,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount[i]); + } } } + internal class LightenSrcIn : PixelBlender { /// @@ -1327,31 +1137,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount[i]); + } } } + internal class OverlaySrcIn : PixelBlender { /// @@ -1366,31 +1170,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlaySrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount[i]); + } } } + internal class HardLightSrcIn : PixelBlender { /// @@ -1405,31 +1203,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightSrcIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount[i]); + } } } + internal class NormalSrcOut : PixelBlender { /// @@ -1444,31 +1236,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount[i]); + } } } + internal class MultiplySrcOut : PixelBlender { /// @@ -1483,31 +1269,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplySrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount[i]); + } } } + internal class AddSrcOut : PixelBlender { /// @@ -1522,31 +1302,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount[i]); + } } } + internal class SubtractSrcOut : PixelBlender { /// @@ -1561,31 +1335,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount[i]); + } } } + internal class ScreenSrcOut : PixelBlender { /// @@ -1600,31 +1368,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount[i]); + } } } + internal class DarkenSrcOut : PixelBlender { /// @@ -1639,31 +1401,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount[i]); + } } } + internal class LightenSrcOut : PixelBlender { /// @@ -1678,31 +1434,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount[i]); + } } } + internal class OverlaySrcOut : PixelBlender { /// @@ -1717,31 +1467,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlaySrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount[i]); + } } } + internal class HardLightSrcOut : PixelBlender { /// @@ -1756,31 +1500,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightSrcOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount[i]); + } } } + internal class NormalDest : PixelBlender { /// @@ -1795,31 +1533,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalDest(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount[i]); + } } } + internal class MultiplyDest : PixelBlender { /// @@ -1834,31 +1566,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplyDest(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount[i]); + } } } + internal class AddDest : PixelBlender { /// @@ -1873,31 +1599,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddDest(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount[i]); + } } } + internal class SubtractDest : PixelBlender { /// @@ -1912,31 +1632,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractDest(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount[i]); + } } } + internal class ScreenDest : PixelBlender { /// @@ -1951,31 +1665,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenDest(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount[i]); + } } } + internal class DarkenDest : PixelBlender { /// @@ -1990,31 +1698,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenDest(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount[i]); + } } } + internal class LightenDest : PixelBlender { /// @@ -2029,31 +1731,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenDest(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount[i]); + } } } + internal class OverlayDest : PixelBlender { /// @@ -2068,31 +1764,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlayDest(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount[i]); + } } } + internal class HardLightDest : PixelBlender { /// @@ -2107,31 +1797,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightDest(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount[i]); + } } } + internal class NormalDestAtop : PixelBlender { /// @@ -2146,31 +1830,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount[i]); + } } } + internal class MultiplyDestAtop : PixelBlender { /// @@ -2185,31 +1863,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplyDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount[i]); + } } } + internal class AddDestAtop : PixelBlender { /// @@ -2224,31 +1896,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount[i]); + } } } + internal class SubtractDestAtop : PixelBlender { /// @@ -2263,31 +1929,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount[i]); + } } } + internal class ScreenDestAtop : PixelBlender { /// @@ -2302,31 +1962,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount[i]); + } } } + internal class DarkenDestAtop : PixelBlender { /// @@ -2341,31 +1995,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount[i]); + } } } + internal class LightenDestAtop : PixelBlender { /// @@ -2380,31 +2028,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount[i]); + } } } + internal class OverlayDestAtop : PixelBlender { /// @@ -2419,31 +2061,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlayDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount[i]); + } } } + internal class HardLightDestAtop : PixelBlender { /// @@ -2458,31 +2094,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightDestAtop(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount[i]); + } } } + internal class NormalDestOver : PixelBlender { /// @@ -2497,31 +2127,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount[i]); + } } } + internal class MultiplyDestOver : PixelBlender { /// @@ -2536,31 +2160,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplyDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount[i]); + } } } + internal class AddDestOver : PixelBlender { /// @@ -2575,31 +2193,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount[i]); + } } } + internal class SubtractDestOver : PixelBlender { /// @@ -2614,31 +2226,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount[i]); + } } } + internal class ScreenDestOver : PixelBlender { /// @@ -2653,31 +2259,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount[i]); + } } } + internal class DarkenDestOver : PixelBlender { /// @@ -2692,31 +2292,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount[i]); + } } } + internal class LightenDestOver : PixelBlender { /// @@ -2731,31 +2325,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount[i]); + } } } + internal class OverlayDestOver : PixelBlender { /// @@ -2770,31 +2358,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlayDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount[i]); + } } } + internal class HardLightDestOver : PixelBlender { /// @@ -2809,31 +2391,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightDestOver(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount[i]); + } } } + internal class NormalDestIn : PixelBlender { /// @@ -2848,31 +2424,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount[i]); + } } } + internal class MultiplyDestIn : PixelBlender { /// @@ -2887,31 +2457,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplyDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount[i]); + } } } + internal class AddDestIn : PixelBlender { /// @@ -2926,31 +2490,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount[i]); + } } } + internal class SubtractDestIn : PixelBlender { /// @@ -2965,31 +2523,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount[i]); + } } } + internal class ScreenDestIn : PixelBlender { /// @@ -3004,31 +2556,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount[i]); + } } } + internal class DarkenDestIn : PixelBlender { /// @@ -3043,31 +2589,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount[i]); + } } } + internal class LightenDestIn : PixelBlender { /// @@ -3082,31 +2622,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount[i]); + } } } + internal class OverlayDestIn : PixelBlender { /// @@ -3121,31 +2655,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlayDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount[i]); + } } } + internal class HardLightDestIn : PixelBlender { /// @@ -3160,31 +2688,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightDestIn(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount[i]); + } } } + internal class NormalDestOut : PixelBlender { /// @@ -3199,31 +2721,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount[i]); + } } } + internal class MultiplyDestOut : PixelBlender { /// @@ -3238,31 +2754,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplyDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount[i]); + } } } + internal class AddDestOut : PixelBlender { /// @@ -3277,31 +2787,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount[i]); + } } } + internal class SubtractDestOut : PixelBlender { /// @@ -3316,31 +2820,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount[i]); + } } } + internal class ScreenDestOut : PixelBlender { /// @@ -3355,31 +2853,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount[i]); + } } } + internal class DarkenDestOut : PixelBlender { /// @@ -3394,31 +2886,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount[i]); + } } } + internal class LightenDestOut : PixelBlender { /// @@ -3433,31 +2919,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount[i]); + } } } + internal class OverlayDestOut : PixelBlender { /// @@ -3472,31 +2952,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlayDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount[i]); + } } } + internal class HardLightDestOut : PixelBlender { /// @@ -3511,31 +2985,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightDestOut(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount[i]); + } } } + internal class NormalClear : PixelBlender { /// @@ -3550,31 +3018,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalClear(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount[i]); + } } } + internal class MultiplyClear : PixelBlender { /// @@ -3589,31 +3051,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplyClear(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount[i]); + } } } + internal class AddClear : PixelBlender { /// @@ -3628,31 +3084,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddClear(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount[i]); + } } } + internal class SubtractClear : PixelBlender { /// @@ -3667,31 +3117,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractClear(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount[i]); + } } } + internal class ScreenClear : PixelBlender { /// @@ -3706,31 +3150,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenClear(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount[i]); + } } } + internal class DarkenClear : PixelBlender { /// @@ -3745,31 +3183,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenClear(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount[i]); + } } } + internal class LightenClear : PixelBlender { /// @@ -3784,31 +3216,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenClear(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount[i]); + } } } + internal class OverlayClear : PixelBlender { /// @@ -3823,31 +3249,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlayClear(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount[i]); + } } } + internal class HardLightClear : PixelBlender { /// @@ -3862,31 +3282,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightClear(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount[i]); + } } } + internal class NormalXor : PixelBlender { /// @@ -3901,31 +3315,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.NormalXor(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount[i]); + } } } + internal class MultiplyXor : PixelBlender { /// @@ -3940,31 +3348,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.MultiplyXor(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount[i]); + } } } + internal class AddXor : PixelBlender { /// @@ -3979,31 +3381,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.AddXor(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount[i]); + } } } + internal class SubtractXor : PixelBlender { /// @@ -4018,31 +3414,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.SubtractXor(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount[i]); + } } } + internal class ScreenXor : PixelBlender { /// @@ -4057,31 +3447,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.ScreenXor(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount[i]); + } } } + internal class DarkenXor : PixelBlender { /// @@ -4096,31 +3480,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.DarkenXor(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount[i]); + } } } + internal class LightenXor : PixelBlender { /// @@ -4135,31 +3513,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.LightenXor(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount[i]); + } } } + internal class OverlayXor : PixelBlender { /// @@ -4174,31 +3546,25 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.OverlayXor(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount[i]); + } } } + internal class HardLightXor : PixelBlender { /// @@ -4213,30 +3579,24 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.HardLightXor(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount[i]); + } } } + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index 34fe4d4cda..85dbd7091e 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -12,9 +12,11 @@ // Licensed under the Apache License, Version 2.0. // -using System; -using System.Numerics; -using System.Buffers; +using System; +using System.Numerics; +using System.Buffers; + +using SixLabors.ImageSharp.Memory; using SixLabors.Memory; namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders @@ -82,28 +84,21 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } /// - public override void Blend(MemoryAllocator memoryManager, Span destination, Span background, Span source, Span amount) + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + for (int i = 0; i < destination.Length; i++) { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - for (int i = 0; i < destination.Length; i++) - { - destinationSpan[i] = PorterDuffFunctions.<#=blender_composer#>(backgroundSpan[i], sourceSpan[i], amount[i]); - } + destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); + } + } - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount[i]); + } } } diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index b8b97ea0a4..0180ef36c6 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -2,6 +2,9 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; +using System.Numerics; +using SixLabors.ImageSharp.Memory; using SixLabors.Memory; namespace SixLabors.ImageSharp.PixelFormats @@ -23,19 +26,130 @@ namespace SixLabors.ImageSharp.PixelFormats /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// /// The final pixel value after composition - public abstract TPixel Blend(TPixel background, TPixel source, float amount); - - /// - /// Blend 2 pixels together. - /// - /// The - /// The destination span. - /// The background span. - /// The source span. + public abstract TPixel Blend(TPixel background, TPixel source, float amount); + + /// + /// Blend 2 rows together. + /// + /// destination span + /// the background span + /// the source span /// /// A value between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. - /// - public abstract void Blend(MemoryAllocator memoryAllocator, Span destination, Span background, Span source, Span amount); + /// + protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount); + + /// + /// Blend 2 rows together. + /// + /// destination span + /// the background span + /// the source span + /// + /// A span with values between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + protected abstract void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount); + + /// + /// Blends 2 rows together + /// + /// the pixel format of the source span + /// memory manager to use internally + /// the destination span + /// the background span + /// the source span + /// + /// A span with values between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + where TPixelSrc : struct, IPixel + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + + /// + /// Blends 2 rows together + /// + /// the pixel format of the source span + /// memory manager to use internally + /// the destination span + /// the background span + /// the source span + /// + /// A value between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + where TPixelSrc : struct, IPixel + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeBetweenOrEqualTo(amount, 0, 1, nameof(amount)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } + + /// + /// Blends 2 rows together + /// + /// memory manager to use internally + /// the destination span + /// the background span + /// the source span + /// + /// A span with values between 0 and 1 indicating the weight of the second source vector. + /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. + /// + public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); + Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + + using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) + { + Span destinationSpan = buffer.Slice(0, destination.Length); + Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); + Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); + + PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + + this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); + + PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + } + } } } From 31dde0edab754eb58396debdb855321217c16e78 Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Wed, 29 Aug 2018 13:13:00 +0200 Subject: [PATCH 032/185] removed a redundant opacity.Clamp(0,1) in the innermost level of pixel blenders. Pixel blenders are performance critical, so every tiny performance improvement counts. --- .../DefaultPixelBlenders.Generated.cs | 432 +++++++++--------- .../DefaultPixelBlenders.Generated.tt | 4 +- .../PorterDuffFunctions.Generated.cs | 297 ++++++++---- .../PorterDuffFunctions.Generated.tt | 33 +- .../PixelFormats/PixelBlender{TPixel}.cs | 38 +- 5 files changed, 449 insertions(+), 355 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index cc6743d567..0aac25bd00 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrc(background, source, amount); + return PorterDuffFunctions.NormalSrc(background, source, amount.Clamp(0,1)); } /// @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount.Clamp(0,1)); } } @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrc(background, source, amount); + return PorterDuffFunctions.MultiplySrc(background, source, amount.Clamp(0,1)); } /// @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount.Clamp(0,1)); } } @@ -110,7 +110,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrc(background, source, amount); + return PorterDuffFunctions.AddSrc(background, source, amount.Clamp(0,1)); } /// @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount.Clamp(0,1)); } } @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrc(background, source, amount); + return PorterDuffFunctions.SubtractSrc(background, source, amount.Clamp(0,1)); } /// @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount.Clamp(0,1)); } } @@ -176,7 +176,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrc(background, source, amount); + return PorterDuffFunctions.ScreenSrc(background, source, amount.Clamp(0,1)); } /// @@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount.Clamp(0,1)); } } @@ -209,7 +209,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrc(background, source, amount); + return PorterDuffFunctions.DarkenSrc(background, source, amount.Clamp(0,1)); } /// @@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount.Clamp(0,1)); } } @@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrc(background, source, amount); + return PorterDuffFunctions.LightenSrc(background, source, amount.Clamp(0,1)); } /// @@ -250,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount.Clamp(0,1)); } } @@ -275,7 +275,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrc(background, source, amount); + return PorterDuffFunctions.OverlaySrc(background, source, amount.Clamp(0,1)); } /// @@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount.Clamp(0,1)); } } @@ -308,7 +308,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrc(background, source, amount); + return PorterDuffFunctions.HardLightSrc(background, source, amount.Clamp(0,1)); } /// @@ -316,7 +316,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount.Clamp(0,1)); } } @@ -341,7 +341,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrcAtop(background, source, amount); + return PorterDuffFunctions.NormalSrcAtop(background, source, amount.Clamp(0,1)); } /// @@ -349,7 +349,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -374,7 +374,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrcAtop(background, source, amount); + return PorterDuffFunctions.MultiplySrcAtop(background, source, amount.Clamp(0,1)); } /// @@ -382,7 +382,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -407,7 +407,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrcAtop(background, source, amount); + return PorterDuffFunctions.AddSrcAtop(background, source, amount.Clamp(0,1)); } /// @@ -415,7 +415,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -440,7 +440,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrcAtop(background, source, amount); + return PorterDuffFunctions.SubtractSrcAtop(background, source, amount.Clamp(0,1)); } /// @@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -473,7 +473,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrcAtop(background, source, amount); + return PorterDuffFunctions.ScreenSrcAtop(background, source, amount.Clamp(0,1)); } /// @@ -481,7 +481,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -506,7 +506,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrcAtop(background, source, amount); + return PorterDuffFunctions.DarkenSrcAtop(background, source, amount.Clamp(0,1)); } /// @@ -514,7 +514,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -539,7 +539,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrcAtop(background, source, amount); + return PorterDuffFunctions.LightenSrcAtop(background, source, amount.Clamp(0,1)); } /// @@ -547,7 +547,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -572,7 +572,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrcAtop(background, source, amount); + return PorterDuffFunctions.OverlaySrcAtop(background, source, amount.Clamp(0,1)); } /// @@ -580,7 +580,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -605,7 +605,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrcAtop(background, source, amount); + return PorterDuffFunctions.HardLightSrcAtop(background, source, amount.Clamp(0,1)); } /// @@ -613,7 +613,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -638,7 +638,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrcOver(background, source, amount); + return PorterDuffFunctions.NormalSrcOver(background, source, amount.Clamp(0,1)); } /// @@ -646,7 +646,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -671,7 +671,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrcOver(background, source, amount); + return PorterDuffFunctions.MultiplySrcOver(background, source, amount.Clamp(0,1)); } /// @@ -679,7 +679,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -704,7 +704,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrcOver(background, source, amount); + return PorterDuffFunctions.AddSrcOver(background, source, amount.Clamp(0,1)); } /// @@ -712,7 +712,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -737,7 +737,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrcOver(background, source, amount); + return PorterDuffFunctions.SubtractSrcOver(background, source, amount.Clamp(0,1)); } /// @@ -745,7 +745,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -770,7 +770,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrcOver(background, source, amount); + return PorterDuffFunctions.ScreenSrcOver(background, source, amount.Clamp(0,1)); } /// @@ -778,7 +778,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -803,7 +803,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrcOver(background, source, amount); + return PorterDuffFunctions.DarkenSrcOver(background, source, amount.Clamp(0,1)); } /// @@ -811,7 +811,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -836,7 +836,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrcOver(background, source, amount); + return PorterDuffFunctions.LightenSrcOver(background, source, amount.Clamp(0,1)); } /// @@ -844,7 +844,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -869,7 +869,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrcOver(background, source, amount); + return PorterDuffFunctions.OverlaySrcOver(background, source, amount.Clamp(0,1)); } /// @@ -877,7 +877,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -902,7 +902,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrcOver(background, source, amount); + return PorterDuffFunctions.HardLightSrcOver(background, source, amount.Clamp(0,1)); } /// @@ -910,7 +910,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -935,7 +935,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrcIn(background, source, amount); + return PorterDuffFunctions.NormalSrcIn(background, source, amount.Clamp(0,1)); } /// @@ -943,7 +943,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -968,7 +968,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrcIn(background, source, amount); + return PorterDuffFunctions.MultiplySrcIn(background, source, amount.Clamp(0,1)); } /// @@ -976,7 +976,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -1001,7 +1001,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrcIn(background, source, amount); + return PorterDuffFunctions.AddSrcIn(background, source, amount.Clamp(0,1)); } /// @@ -1009,7 +1009,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -1034,7 +1034,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrcIn(background, source, amount); + return PorterDuffFunctions.SubtractSrcIn(background, source, amount.Clamp(0,1)); } /// @@ -1042,7 +1042,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -1067,7 +1067,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrcIn(background, source, amount); + return PorterDuffFunctions.ScreenSrcIn(background, source, amount.Clamp(0,1)); } /// @@ -1075,7 +1075,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -1100,7 +1100,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrcIn(background, source, amount); + return PorterDuffFunctions.DarkenSrcIn(background, source, amount.Clamp(0,1)); } /// @@ -1108,7 +1108,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -1133,7 +1133,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrcIn(background, source, amount); + return PorterDuffFunctions.LightenSrcIn(background, source, amount.Clamp(0,1)); } /// @@ -1141,7 +1141,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -1166,7 +1166,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrcIn(background, source, amount); + return PorterDuffFunctions.OverlaySrcIn(background, source, amount.Clamp(0,1)); } /// @@ -1174,7 +1174,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -1199,7 +1199,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrcIn(background, source, amount); + return PorterDuffFunctions.HardLightSrcIn(background, source, amount.Clamp(0,1)); } /// @@ -1207,7 +1207,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -1232,7 +1232,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrcOut(background, source, amount); + return PorterDuffFunctions.NormalSrcOut(background, source, amount.Clamp(0,1)); } /// @@ -1240,7 +1240,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -1265,7 +1265,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrcOut(background, source, amount); + return PorterDuffFunctions.MultiplySrcOut(background, source, amount.Clamp(0,1)); } /// @@ -1273,7 +1273,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -1298,7 +1298,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrcOut(background, source, amount); + return PorterDuffFunctions.AddSrcOut(background, source, amount.Clamp(0,1)); } /// @@ -1306,7 +1306,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -1331,7 +1331,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrcOut(background, source, amount); + return PorterDuffFunctions.SubtractSrcOut(background, source, amount.Clamp(0,1)); } /// @@ -1339,7 +1339,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -1364,7 +1364,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrcOut(background, source, amount); + return PorterDuffFunctions.ScreenSrcOut(background, source, amount.Clamp(0,1)); } /// @@ -1372,7 +1372,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -1397,7 +1397,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrcOut(background, source, amount); + return PorterDuffFunctions.DarkenSrcOut(background, source, amount.Clamp(0,1)); } /// @@ -1405,7 +1405,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -1430,7 +1430,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrcOut(background, source, amount); + return PorterDuffFunctions.LightenSrcOut(background, source, amount.Clamp(0,1)); } /// @@ -1438,7 +1438,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -1463,7 +1463,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrcOut(background, source, amount); + return PorterDuffFunctions.OverlaySrcOut(background, source, amount.Clamp(0,1)); } /// @@ -1471,7 +1471,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -1496,7 +1496,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrcOut(background, source, amount); + return PorterDuffFunctions.HardLightSrcOut(background, source, amount.Clamp(0,1)); } /// @@ -1504,7 +1504,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -1529,7 +1529,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDest(background, source, amount); + return PorterDuffFunctions.NormalDest(background, source, amount.Clamp(0,1)); } /// @@ -1537,7 +1537,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount.Clamp(0,1)); } } @@ -1562,7 +1562,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDest(background, source, amount); + return PorterDuffFunctions.MultiplyDest(background, source, amount.Clamp(0,1)); } /// @@ -1570,7 +1570,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount.Clamp(0,1)); } } @@ -1595,7 +1595,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDest(background, source, amount); + return PorterDuffFunctions.AddDest(background, source, amount.Clamp(0,1)); } /// @@ -1603,7 +1603,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount.Clamp(0,1)); } } @@ -1628,7 +1628,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDest(background, source, amount); + return PorterDuffFunctions.SubtractDest(background, source, amount.Clamp(0,1)); } /// @@ -1636,7 +1636,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount.Clamp(0,1)); } } @@ -1661,7 +1661,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDest(background, source, amount); + return PorterDuffFunctions.ScreenDest(background, source, amount.Clamp(0,1)); } /// @@ -1669,7 +1669,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount.Clamp(0,1)); } } @@ -1694,7 +1694,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDest(background, source, amount); + return PorterDuffFunctions.DarkenDest(background, source, amount.Clamp(0,1)); } /// @@ -1702,7 +1702,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount.Clamp(0,1)); } } @@ -1727,7 +1727,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDest(background, source, amount); + return PorterDuffFunctions.LightenDest(background, source, amount.Clamp(0,1)); } /// @@ -1735,7 +1735,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount.Clamp(0,1)); } } @@ -1760,7 +1760,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDest(background, source, amount); + return PorterDuffFunctions.OverlayDest(background, source, amount.Clamp(0,1)); } /// @@ -1768,7 +1768,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount.Clamp(0,1)); } } @@ -1793,7 +1793,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDest(background, source, amount); + return PorterDuffFunctions.HardLightDest(background, source, amount.Clamp(0,1)); } /// @@ -1801,7 +1801,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount.Clamp(0,1)); } } @@ -1826,7 +1826,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDestAtop(background, source, amount); + return PorterDuffFunctions.NormalDestAtop(background, source, amount.Clamp(0,1)); } /// @@ -1834,7 +1834,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -1859,7 +1859,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDestAtop(background, source, amount); + return PorterDuffFunctions.MultiplyDestAtop(background, source, amount.Clamp(0,1)); } /// @@ -1867,7 +1867,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -1892,7 +1892,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDestAtop(background, source, amount); + return PorterDuffFunctions.AddDestAtop(background, source, amount.Clamp(0,1)); } /// @@ -1900,7 +1900,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -1925,7 +1925,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDestAtop(background, source, amount); + return PorterDuffFunctions.SubtractDestAtop(background, source, amount.Clamp(0,1)); } /// @@ -1933,7 +1933,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -1958,7 +1958,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDestAtop(background, source, amount); + return PorterDuffFunctions.ScreenDestAtop(background, source, amount.Clamp(0,1)); } /// @@ -1966,7 +1966,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -1991,7 +1991,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDestAtop(background, source, amount); + return PorterDuffFunctions.DarkenDestAtop(background, source, amount.Clamp(0,1)); } /// @@ -1999,7 +1999,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -2024,7 +2024,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDestAtop(background, source, amount); + return PorterDuffFunctions.LightenDestAtop(background, source, amount.Clamp(0,1)); } /// @@ -2032,7 +2032,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -2057,7 +2057,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDestAtop(background, source, amount); + return PorterDuffFunctions.OverlayDestAtop(background, source, amount.Clamp(0,1)); } /// @@ -2065,7 +2065,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -2090,7 +2090,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDestAtop(background, source, amount); + return PorterDuffFunctions.HardLightDestAtop(background, source, amount.Clamp(0,1)); } /// @@ -2098,7 +2098,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount.Clamp(0,1)); } } @@ -2123,7 +2123,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDestOver(background, source, amount); + return PorterDuffFunctions.NormalDestOver(background, source, amount.Clamp(0,1)); } /// @@ -2131,7 +2131,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -2156,7 +2156,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDestOver(background, source, amount); + return PorterDuffFunctions.MultiplyDestOver(background, source, amount.Clamp(0,1)); } /// @@ -2164,7 +2164,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -2189,7 +2189,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDestOver(background, source, amount); + return PorterDuffFunctions.AddDestOver(background, source, amount.Clamp(0,1)); } /// @@ -2197,7 +2197,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -2222,7 +2222,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDestOver(background, source, amount); + return PorterDuffFunctions.SubtractDestOver(background, source, amount.Clamp(0,1)); } /// @@ -2230,7 +2230,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -2255,7 +2255,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDestOver(background, source, amount); + return PorterDuffFunctions.ScreenDestOver(background, source, amount.Clamp(0,1)); } /// @@ -2263,7 +2263,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -2288,7 +2288,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDestOver(background, source, amount); + return PorterDuffFunctions.DarkenDestOver(background, source, amount.Clamp(0,1)); } /// @@ -2296,7 +2296,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -2321,7 +2321,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDestOver(background, source, amount); + return PorterDuffFunctions.LightenDestOver(background, source, amount.Clamp(0,1)); } /// @@ -2329,7 +2329,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -2354,7 +2354,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDestOver(background, source, amount); + return PorterDuffFunctions.OverlayDestOver(background, source, amount.Clamp(0,1)); } /// @@ -2362,7 +2362,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -2387,7 +2387,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDestOver(background, source, amount); + return PorterDuffFunctions.HardLightDestOver(background, source, amount.Clamp(0,1)); } /// @@ -2395,7 +2395,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount.Clamp(0,1)); } } @@ -2420,7 +2420,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDestIn(background, source, amount); + return PorterDuffFunctions.NormalDestIn(background, source, amount.Clamp(0,1)); } /// @@ -2428,7 +2428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -2453,7 +2453,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDestIn(background, source, amount); + return PorterDuffFunctions.MultiplyDestIn(background, source, amount.Clamp(0,1)); } /// @@ -2461,7 +2461,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -2486,7 +2486,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDestIn(background, source, amount); + return PorterDuffFunctions.AddDestIn(background, source, amount.Clamp(0,1)); } /// @@ -2494,7 +2494,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -2519,7 +2519,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDestIn(background, source, amount); + return PorterDuffFunctions.SubtractDestIn(background, source, amount.Clamp(0,1)); } /// @@ -2527,7 +2527,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -2552,7 +2552,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDestIn(background, source, amount); + return PorterDuffFunctions.ScreenDestIn(background, source, amount.Clamp(0,1)); } /// @@ -2560,7 +2560,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -2585,7 +2585,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDestIn(background, source, amount); + return PorterDuffFunctions.DarkenDestIn(background, source, amount.Clamp(0,1)); } /// @@ -2593,7 +2593,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -2618,7 +2618,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDestIn(background, source, amount); + return PorterDuffFunctions.LightenDestIn(background, source, amount.Clamp(0,1)); } /// @@ -2626,7 +2626,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -2651,7 +2651,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDestIn(background, source, amount); + return PorterDuffFunctions.OverlayDestIn(background, source, amount.Clamp(0,1)); } /// @@ -2659,7 +2659,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -2684,7 +2684,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDestIn(background, source, amount); + return PorterDuffFunctions.HardLightDestIn(background, source, amount.Clamp(0,1)); } /// @@ -2692,7 +2692,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount.Clamp(0,1)); } } @@ -2717,7 +2717,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDestOut(background, source, amount); + return PorterDuffFunctions.NormalDestOut(background, source, amount.Clamp(0,1)); } /// @@ -2725,7 +2725,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -2750,7 +2750,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDestOut(background, source, amount); + return PorterDuffFunctions.MultiplyDestOut(background, source, amount.Clamp(0,1)); } /// @@ -2758,7 +2758,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -2783,7 +2783,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDestOut(background, source, amount); + return PorterDuffFunctions.AddDestOut(background, source, amount.Clamp(0,1)); } /// @@ -2791,7 +2791,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -2816,7 +2816,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDestOut(background, source, amount); + return PorterDuffFunctions.SubtractDestOut(background, source, amount.Clamp(0,1)); } /// @@ -2824,7 +2824,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -2849,7 +2849,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDestOut(background, source, amount); + return PorterDuffFunctions.ScreenDestOut(background, source, amount.Clamp(0,1)); } /// @@ -2857,7 +2857,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -2882,7 +2882,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDestOut(background, source, amount); + return PorterDuffFunctions.DarkenDestOut(background, source, amount.Clamp(0,1)); } /// @@ -2890,7 +2890,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -2915,7 +2915,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDestOut(background, source, amount); + return PorterDuffFunctions.LightenDestOut(background, source, amount.Clamp(0,1)); } /// @@ -2923,7 +2923,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -2948,7 +2948,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDestOut(background, source, amount); + return PorterDuffFunctions.OverlayDestOut(background, source, amount.Clamp(0,1)); } /// @@ -2956,7 +2956,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -2981,7 +2981,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDestOut(background, source, amount); + return PorterDuffFunctions.HardLightDestOut(background, source, amount.Clamp(0,1)); } /// @@ -2989,7 +2989,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount.Clamp(0,1)); } } @@ -3014,7 +3014,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalClear(background, source, amount); + return PorterDuffFunctions.NormalClear(background, source, amount.Clamp(0,1)); } /// @@ -3022,7 +3022,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount.Clamp(0,1)); } } @@ -3047,7 +3047,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyClear(background, source, amount); + return PorterDuffFunctions.MultiplyClear(background, source, amount.Clamp(0,1)); } /// @@ -3055,7 +3055,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount.Clamp(0,1)); } } @@ -3080,7 +3080,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddClear(background, source, amount); + return PorterDuffFunctions.AddClear(background, source, amount.Clamp(0,1)); } /// @@ -3088,7 +3088,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount.Clamp(0,1)); } } @@ -3113,7 +3113,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractClear(background, source, amount); + return PorterDuffFunctions.SubtractClear(background, source, amount.Clamp(0,1)); } /// @@ -3121,7 +3121,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount.Clamp(0,1)); } } @@ -3146,7 +3146,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenClear(background, source, amount); + return PorterDuffFunctions.ScreenClear(background, source, amount.Clamp(0,1)); } /// @@ -3154,7 +3154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount.Clamp(0,1)); } } @@ -3179,7 +3179,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenClear(background, source, amount); + return PorterDuffFunctions.DarkenClear(background, source, amount.Clamp(0,1)); } /// @@ -3187,7 +3187,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount.Clamp(0,1)); } } @@ -3212,7 +3212,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenClear(background, source, amount); + return PorterDuffFunctions.LightenClear(background, source, amount.Clamp(0,1)); } /// @@ -3220,7 +3220,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount.Clamp(0,1)); } } @@ -3245,7 +3245,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayClear(background, source, amount); + return PorterDuffFunctions.OverlayClear(background, source, amount.Clamp(0,1)); } /// @@ -3253,7 +3253,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount.Clamp(0,1)); } } @@ -3278,7 +3278,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightClear(background, source, amount); + return PorterDuffFunctions.HardLightClear(background, source, amount.Clamp(0,1)); } /// @@ -3286,7 +3286,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount.Clamp(0,1)); } } @@ -3311,7 +3311,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalXor(background, source, amount); + return PorterDuffFunctions.NormalXor(background, source, amount.Clamp(0,1)); } /// @@ -3319,7 +3319,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount.Clamp(0,1)); } } @@ -3344,7 +3344,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyXor(background, source, amount); + return PorterDuffFunctions.MultiplyXor(background, source, amount.Clamp(0,1)); } /// @@ -3352,7 +3352,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount.Clamp(0,1)); } } @@ -3377,7 +3377,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddXor(background, source, amount); + return PorterDuffFunctions.AddXor(background, source, amount.Clamp(0,1)); } /// @@ -3385,7 +3385,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount.Clamp(0,1)); } } @@ -3410,7 +3410,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractXor(background, source, amount); + return PorterDuffFunctions.SubtractXor(background, source, amount.Clamp(0,1)); } /// @@ -3418,7 +3418,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount.Clamp(0,1)); } } @@ -3443,7 +3443,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenXor(background, source, amount); + return PorterDuffFunctions.ScreenXor(background, source, amount.Clamp(0,1)); } /// @@ -3451,7 +3451,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount.Clamp(0,1)); } } @@ -3476,7 +3476,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenXor(background, source, amount); + return PorterDuffFunctions.DarkenXor(background, source, amount.Clamp(0,1)); } /// @@ -3484,7 +3484,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount.Clamp(0,1)); } } @@ -3509,7 +3509,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenXor(background, source, amount); + return PorterDuffFunctions.LightenXor(background, source, amount.Clamp(0,1)); } /// @@ -3517,7 +3517,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount.Clamp(0,1)); } } @@ -3542,7 +3542,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayXor(background, source, amount); + return PorterDuffFunctions.OverlayXor(background, source, amount.Clamp(0,1)); } /// @@ -3550,7 +3550,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount.Clamp(0,1)); } } @@ -3575,7 +3575,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightXor(background, source, amount); + return PorterDuffFunctions.HardLightXor(background, source, amount.Clamp(0,1)); } /// @@ -3583,7 +3583,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount.Clamp(0,1)); } } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index 85dbd7091e..17e93d9d74 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.<#=blender_composer#>(background, source, amount); + return PorterDuffFunctions.<#=blender_composer#>(background, source, amount.Clamp(0,1)); } /// @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); + destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount.Clamp(0,1)); } } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index 4b0ffdd485..841f6ea856 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -19,7 +19,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrc(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -28,7 +29,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, Normal(backdrop, source)); @@ -37,7 +39,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, Normal(backdrop, source)); @@ -46,7 +49,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, Normal(backdrop, source)); @@ -55,7 +59,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -70,7 +75,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, Normal(source, backdrop)); @@ -79,7 +85,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, Normal(source, backdrop)); @@ -88,7 +95,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, Normal(source, backdrop)); @@ -97,7 +105,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -106,7 +115,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalXor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -115,7 +125,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalClear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); @@ -256,7 +267,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrc(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -265,7 +277,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, Multiply(backdrop, source)); @@ -274,7 +287,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, Multiply(backdrop, source)); @@ -283,7 +297,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, Multiply(backdrop, source)); @@ -292,7 +307,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -307,7 +323,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, Multiply(source, backdrop)); @@ -316,7 +333,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, Multiply(source, backdrop)); @@ -325,7 +343,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, Multiply(source, backdrop)); @@ -334,7 +353,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -343,7 +363,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyXor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -352,7 +373,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyClear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); @@ -493,7 +515,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrc(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -502,7 +525,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, Add(backdrop, source)); @@ -511,7 +535,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, Add(backdrop, source)); @@ -520,7 +545,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, Add(backdrop, source)); @@ -529,7 +555,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -544,7 +571,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, Add(source, backdrop)); @@ -553,7 +581,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, Add(source, backdrop)); @@ -562,7 +591,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, Add(source, backdrop)); @@ -571,7 +601,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -580,7 +611,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddXor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -589,7 +621,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddClear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); @@ -730,7 +763,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrc(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -739,7 +773,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, Subtract(backdrop, source)); @@ -748,7 +783,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, Subtract(backdrop, source)); @@ -757,7 +793,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, Subtract(backdrop, source)); @@ -766,7 +803,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -781,7 +819,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, Subtract(source, backdrop)); @@ -790,7 +829,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, Subtract(source, backdrop)); @@ -799,7 +839,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, Subtract(source, backdrop)); @@ -808,7 +849,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -817,7 +859,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractXor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -826,7 +869,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractClear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); @@ -967,7 +1011,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrc(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -976,7 +1021,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, Screen(backdrop, source)); @@ -985,7 +1031,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, Screen(backdrop, source)); @@ -994,7 +1041,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, Screen(backdrop, source)); @@ -1003,7 +1051,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -1018,7 +1067,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, Screen(source, backdrop)); @@ -1027,7 +1077,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, Screen(source, backdrop)); @@ -1036,7 +1087,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, Screen(source, backdrop)); @@ -1045,7 +1097,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -1054,7 +1107,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenXor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -1063,7 +1117,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenClear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); @@ -1204,7 +1259,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrc(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -1213,7 +1269,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, Darken(backdrop, source)); @@ -1222,7 +1279,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, Darken(backdrop, source)); @@ -1231,7 +1289,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, Darken(backdrop, source)); @@ -1240,7 +1299,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -1255,7 +1315,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, Darken(source, backdrop)); @@ -1264,7 +1325,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, Darken(source, backdrop)); @@ -1273,7 +1335,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, Darken(source, backdrop)); @@ -1282,7 +1345,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -1291,7 +1355,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenXor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -1300,7 +1365,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenClear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); @@ -1441,7 +1507,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrc(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -1450,7 +1517,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, Lighten(backdrop, source)); @@ -1459,7 +1527,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, Lighten(backdrop, source)); @@ -1468,7 +1537,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, Lighten(backdrop, source)); @@ -1477,7 +1547,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -1492,7 +1563,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, Lighten(source, backdrop)); @@ -1501,7 +1573,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, Lighten(source, backdrop)); @@ -1510,7 +1583,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, Lighten(source, backdrop)); @@ -1519,7 +1593,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -1528,7 +1603,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenXor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -1537,7 +1613,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenClear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); @@ -1678,7 +1755,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrc(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -1687,7 +1765,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, Overlay(backdrop, source)); @@ -1696,7 +1775,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, Overlay(backdrop, source)); @@ -1705,7 +1785,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, Overlay(backdrop, source)); @@ -1714,7 +1795,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -1729,7 +1811,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, Overlay(source, backdrop)); @@ -1738,7 +1821,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, Overlay(source, backdrop)); @@ -1747,7 +1831,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, Overlay(source, backdrop)); @@ -1756,7 +1841,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -1765,7 +1851,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayXor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -1774,7 +1861,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayClear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); @@ -1915,7 +2003,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrc(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -1924,7 +2013,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, HardLight(backdrop, source)); @@ -1933,7 +2023,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, HardLight(backdrop, source)); @@ -1942,7 +2033,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, HardLight(backdrop, source)); @@ -1951,7 +2043,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -1966,7 +2059,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, HardLight(source, backdrop)); @@ -1975,7 +2069,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, HardLight(source, backdrop)); @@ -1984,7 +2079,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, HardLight(source, backdrop)); @@ -1993,7 +2089,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -2002,7 +2099,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightXor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -2011,7 +2109,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightClear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 5e46a89a85..7d5b8663df 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -27,7 +27,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Src(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return source; @@ -36,7 +37,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(backdrop, source, <#=blender#>(backdrop, source)); @@ -45,7 +47,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(backdrop, source, <#=blender#>(backdrop, source)); @@ -54,7 +57,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(backdrop, source, <#=blender#>(backdrop, source)); @@ -63,7 +67,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(backdrop, source); @@ -78,7 +83,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestAtop(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Atop(source, backdrop, <#=blender#>(source, backdrop)); @@ -87,7 +93,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestOver(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Over(source, backdrop, <#=blender#>(source, backdrop)); @@ -96,7 +103,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestIn(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return In(source, backdrop, <#=blender#>(source, backdrop)); @@ -105,7 +113,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestOut(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Out(source, backdrop); @@ -114,7 +123,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Xor(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Xor(backdrop, source); @@ -123,7 +133,8 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Clear(Vector4 backdrop, Vector4 source, float opacity) { - opacity = opacity.Clamp(0, 1); + DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + source.W *= opacity; return Clear(backdrop, source); diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 0180ef36c6..bc53fec75a 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -55,7 +55,6 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Blends 2 rows together /// - /// the pixel format of the source span /// memory manager to use internally /// the destination span /// the background span @@ -64,26 +63,9 @@ namespace SixLabors.ImageSharp.PixelFormats /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - where TPixelSrc : struct, IPixel + public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) { - Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); - Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); - - using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) - { - Span destinationSpan = buffer.Slice(0, destination.Length); - Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); - Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - - this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); - } + this.Blend(memoryManager, destination, background, source, amount); } /// @@ -95,15 +77,15 @@ namespace SixLabors.ImageSharp.PixelFormats /// the background span /// the source span /// - /// A value between 0 and 1 indicating the weight of the second source vector. + /// A span with values between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) where TPixelSrc : struct, IPixel { Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeBetweenOrEqualTo(amount, 0, 1, nameof(amount)); + Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { @@ -123,19 +105,21 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// Blends 2 rows together /// + /// the pixel format of the source span /// memory manager to use internally /// the destination span /// the background span /// the source span /// - /// A span with values between 0 and 1 indicating the weight of the second source vector. + /// A value between 0 and 1 indicating the weight of the second source vector. /// At amount = 0, "from" is returned, at amount = 1, "to" is returned. /// - public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + public void Blend(MemoryAllocator memoryManager, Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + where TPixelSrc : struct, IPixel { Guard.MustBeGreaterThanOrEqualTo(background.Length, destination.Length, nameof(background.Length)); Guard.MustBeGreaterThanOrEqualTo(source.Length, destination.Length, nameof(source.Length)); - Guard.MustBeGreaterThanOrEqualTo(amount.Length, destination.Length, nameof(amount.Length)); + Guard.MustBeBetweenOrEqualTo(amount, 0, 1, nameof(amount)); using (IMemoryOwner buffer = memoryManager.Allocate(destination.Length * 3)) { @@ -144,7 +128,7 @@ namespace SixLabors.ImageSharp.PixelFormats Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); From a91532c3b9ed48ca3c00c138d1e82168d7668b3b Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Wed, 29 Aug 2018 14:48:24 +0200 Subject: [PATCH 033/185] moved Clamp(0,1) one level up --- .../DefaultPixelBlenders.Generated.cs | 216 +++++++++--------- .../DefaultPixelBlenders.Generated.tt | 2 +- .../PixelFormats/PixelBlender{TPixel}.cs | 2 +- 3 files changed, 110 insertions(+), 110 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 0aac25bd00..409938f6e3 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount); } } @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount); } } @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount); } } @@ -151,7 +151,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount); } } @@ -184,7 +184,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount); } } @@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount); } } @@ -250,7 +250,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount); } } @@ -283,7 +283,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount); } } @@ -316,7 +316,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount); } } @@ -349,7 +349,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount); } } @@ -382,7 +382,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount); } } @@ -415,7 +415,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount); } } @@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount); } } @@ -481,7 +481,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount); } } @@ -514,7 +514,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount); } } @@ -547,7 +547,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount); } } @@ -580,7 +580,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount); } } @@ -613,7 +613,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount); } } @@ -646,7 +646,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount); } } @@ -679,7 +679,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount); } } @@ -712,7 +712,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount); } } @@ -745,7 +745,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount); } } @@ -778,7 +778,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount); } } @@ -811,7 +811,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount); } } @@ -844,7 +844,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount); } } @@ -877,7 +877,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount); } } @@ -910,7 +910,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount); } } @@ -943,7 +943,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount); } } @@ -976,7 +976,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount); } } @@ -1009,7 +1009,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount); } } @@ -1042,7 +1042,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount); } } @@ -1075,7 +1075,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount); } } @@ -1108,7 +1108,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount); } } @@ -1141,7 +1141,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount); } } @@ -1174,7 +1174,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount); } } @@ -1207,7 +1207,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount); } } @@ -1240,7 +1240,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount); } } @@ -1273,7 +1273,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount); } } @@ -1306,7 +1306,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount); } } @@ -1339,7 +1339,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount); } } @@ -1372,7 +1372,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount); } } @@ -1405,7 +1405,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount); } } @@ -1438,7 +1438,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount); } } @@ -1471,7 +1471,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount); } } @@ -1504,7 +1504,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount); } } @@ -1537,7 +1537,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount); } } @@ -1570,7 +1570,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount); } } @@ -1603,7 +1603,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount); } } @@ -1636,7 +1636,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount); } } @@ -1669,7 +1669,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount); } } @@ -1702,7 +1702,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount); } } @@ -1735,7 +1735,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount); } } @@ -1768,7 +1768,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount); } } @@ -1801,7 +1801,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount); } } @@ -1834,7 +1834,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount); } } @@ -1867,7 +1867,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount); } } @@ -1900,7 +1900,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount); } } @@ -1933,7 +1933,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount); } } @@ -1966,7 +1966,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount); } } @@ -1999,7 +1999,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount); } } @@ -2032,7 +2032,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount); } } @@ -2065,7 +2065,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount); } } @@ -2098,7 +2098,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount); } } @@ -2131,7 +2131,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount); } } @@ -2164,7 +2164,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount); } } @@ -2197,7 +2197,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount); } } @@ -2230,7 +2230,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount); } } @@ -2263,7 +2263,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount); } } @@ -2296,7 +2296,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount); } } @@ -2329,7 +2329,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount); } } @@ -2362,7 +2362,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount); } } @@ -2395,7 +2395,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount); } } @@ -2428,7 +2428,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount); } } @@ -2461,7 +2461,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount); } } @@ -2494,7 +2494,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount); } } @@ -2527,7 +2527,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount); } } @@ -2560,7 +2560,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount); } } @@ -2593,7 +2593,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount); } } @@ -2626,7 +2626,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount); } } @@ -2659,7 +2659,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount); } } @@ -2692,7 +2692,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount); } } @@ -2725,7 +2725,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount); } } @@ -2758,7 +2758,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount); } } @@ -2791,7 +2791,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount); } } @@ -2824,7 +2824,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount); } } @@ -2857,7 +2857,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount); } } @@ -2890,7 +2890,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount); } } @@ -2923,7 +2923,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount); } } @@ -2956,7 +2956,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount); } } @@ -2989,7 +2989,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount); } } @@ -3022,7 +3022,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount); } } @@ -3055,7 +3055,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount); } } @@ -3088,7 +3088,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount); } } @@ -3121,7 +3121,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount); } } @@ -3154,7 +3154,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount); } } @@ -3187,7 +3187,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount); } } @@ -3220,7 +3220,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount); } } @@ -3253,7 +3253,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount); } } @@ -3286,7 +3286,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount); } } @@ -3319,7 +3319,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount); } } @@ -3352,7 +3352,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount); } } @@ -3385,7 +3385,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount); } } @@ -3418,7 +3418,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount); } } @@ -3451,7 +3451,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount); } } @@ -3484,7 +3484,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount); } } @@ -3517,7 +3517,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount); } } @@ -3550,7 +3550,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount); } } @@ -3583,7 +3583,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount); } } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index 17e93d9d74..a61041c86c 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount.Clamp(0,1)); + destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); } } diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index bc53fec75a..8039922f21 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); - this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); + this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount.Clamp(0, 1)); PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); } From 50fbbfd0245ba3a6a7f86748b2804a32d9f43ccc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 31 Aug 2018 23:34:32 +0100 Subject: [PATCH 034/185] Use in where appropriate. --- .../Conversion/ColorSpaceConverter.CieLchuv.cs | 2 +- .../Formats/Jpeg/Components/Block8x8F.CopyTo.cs | 7 +++---- .../ColorConverters/JpegColorConverter.FromCmyk.cs | 2 +- .../ColorConverters/JpegColorConverter.FromGrayScale.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.FromRgb.cs | 2 +- .../ColorConverters/JpegColorConverter.FromYCbCrBasic.cs | 4 ++-- .../ColorConverters/JpegColorConverter.FromYCbCrSimd.cs | 4 ++-- .../JpegColorConverter.FromYCbCrSimdAvx2.cs | 4 ++-- .../ColorConverters/JpegColorConverter.FromYccK.cs | 2 +- .../Decoder/ColorConverters/JpegColorConverter.cs | 2 +- .../Jpeg/Components/Decoder/JpegBlockPostProcessor.cs | 8 +++++--- .../Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs | 2 +- .../Processors/Convolution/Convolution2PassProcessor.cs | 2 +- 13 files changed, 22 insertions(+), 21 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index a44541bdb5..49c25462ea 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -144,7 +144,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The color to convert. /// The - public CieLchuv ToCieLchuv(Rgb color) + public CieLchuv ToCieLchuv(in Rgb color) { CieXyz xyzColor = this.ToCieXyz(color); return this.ToCieLchuv(xyzColor); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs index bebc13f6de..b7dd125a88 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.CopyTo.cs @@ -5,7 +5,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Formats.Jpeg.Components @@ -15,7 +14,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components /// /// Copy block data into the destination color buffer pixel area with the provided horizontal and vertical. /// - public void CopyTo(BufferArea area, int horizontalScale, int verticalScale) + public void CopyTo(in BufferArea area, int horizontalScale, int verticalScale) { if (horizontalScale == 1 && verticalScale == 1) { @@ -57,7 +56,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components } // [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyTo(BufferArea area) + public void CopyTo(in BufferArea area) { ref byte selfBase = ref Unsafe.As(ref this); ref byte destBase = ref Unsafe.As(ref area.GetReferenceToOrigin()); @@ -81,7 +80,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components Unsafe.CopyBlock(ref d, ref s, 8 * sizeof(float)); } - private void CopyTo2x2(BufferArea area) + private void CopyTo2x2(in BufferArea area) { ref float destBase = ref area.GetReferenceToOrigin(); int destStride = area.Stride; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs index bac77f905e..7a14d072e6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromCmyk.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public override void ConvertToRgba(ComponentValues values, Span result) + public override void ConvertToRgba(in ComponentValues values, Span result) { // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! ReadOnlySpan cVals = values.Component0; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs index b07e57e170..5d7a31a12b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromGrayScale.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public override void ConvertToRgba(ComponentValues values, Span result) + public override void ConvertToRgba(in ComponentValues values, Span result) { // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! ReadOnlySpan yVals = values.Component0; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs index 6b7e77e148..7cd97c4140 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromRgb.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public override void ConvertToRgba(ComponentValues values, Span result) + public override void ConvertToRgba(in ComponentValues values, Span result) { // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! ReadOnlySpan rVals = values.Component0; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs index 35700ea312..cb71889bc5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrBasic.cs @@ -15,12 +15,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public override void ConvertToRgba(ComponentValues values, Span result) + public override void ConvertToRgba(in ComponentValues values, Span result) { ConvertCore(values, result); } - internal static void ConvertCore(ComponentValues values, Span result) + internal static void ConvertCore(in ComponentValues values, Span result) { // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! ReadOnlySpan yVals = values.Component0; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs index fd2f17da9e..4b2626c582 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimd.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public override void ConvertToRgba(ComponentValues values, Span result) + public override void ConvertToRgba(in ComponentValues values, Span result) { int remainder = result.Length % 8; int simdCount = result.Length - remainder; @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// /// SIMD convert using buffers of sizes divisable by 8. /// - internal static void ConvertCore(ComponentValues values, Span result) + internal static void ConvertCore(in ComponentValues values, Span result) { DebugGuard.IsTrue(result.Length % 8 == 0, nameof(result), "result.Length should be divisable by 8!"); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs index 25342f4d67..ab4947e65c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYCbCrSimdAvx2.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters public static bool IsAvailable => Vector.IsHardwareAccelerated && SimdUtils.IsAvx2CompatibleArchitecture; - public override void ConvertToRgba(ComponentValues values, Span result) + public override void ConvertToRgba(in ComponentValues values, Span result) { int remainder = result.Length % 8; int simdCount = result.Length - remainder; @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// /// SIMD convert using buffers of sizes divisable by 8. /// - internal static void ConvertCore(ComponentValues values, Span result) + internal static void ConvertCore(in ComponentValues values, Span result) { // This implementation is actually AVX specific. // An AVX register is capable of storing 8 float-s. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs index 83feefa94a..6f940f62f9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.FromYccK.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters { } - public override void ConvertToRgba(ComponentValues values, Span result) + public override void ConvertToRgba(in ComponentValues values, Span result) { // TODO: We can optimize a lot here with Vector and SRCS.Unsafe()! ReadOnlySpan yVals = values.Component0; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs index 8aeb01d7f0..60abb7fb2c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ColorConverters/JpegColorConverter.cs @@ -58,7 +58,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder.ColorConverters /// /// The input as a stack-only struct /// The destination buffer of values - public abstract void ConvertToRgba(ComponentValues values, Span result); + public abstract void ConvertToRgba(in ComponentValues values, Span result); /// /// Returns the for the YCbCr colorspace that matches the current CPU architecture. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs index 900dd3bc89..0108e30815 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBlockPostProcessor.cs @@ -2,9 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Runtime.InteropServices; - using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder @@ -43,6 +41,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Initializes a new instance of the struct. /// + /// The raw jpeg data. + /// The raw component. public JpegBlockPostProcessor(IRawJpegData decoder, IJpegComponent component) { int qtIndex = component.QuantizationTableIndex; @@ -61,9 +61,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// - Level shift by +128, clip to [0, 255] /// - Copy the resultin color values into 'destArea' scaling up the block by amount defined in /// + /// The source block. + /// The destination buffer area. public void ProcessBlockColorsInto( ref Block8x8 sourceBlock, - BufferArea destArea) + in BufferArea destArea) { ref Block8x8F b = ref this.SourceBlock; b.LoadFrom(ref sourceBlock); diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs index 5d7d729b2c..79b9132192 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Matrix.cs @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// The matrix to write /// True if the values are encoded as Single; false if encoded as Fix16 /// The number of bytes written - public int WriteMatrix(DenseMatrix value, bool isSingle) + public int WriteMatrix(in DenseMatrix value, bool isSingle) { int count = 0; for (int y = 0; y < value.Rows; y++) diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 07b2ed064e..0808c07d03 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Buffer2D targetPixels, Buffer2D sourcePixels, Rectangle sourceRectangle, - DenseMatrix kernel, + DenseMatrix kernel, // TODO: Can't use 'in' as pass by ref to lambda expression. Configuration configuration) { int kernelHeight = kernel.Rows; From d45c83193e4b2fefa0ab7153337425de15c9c6ed Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 1 Sep 2018 07:58:15 +0100 Subject: [PATCH 035/185] Fix appveyor build https://github.com/appveyor/ci/issues/2519#issuecomment-405828041 --- appveyor.yml | 2 +- build.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index fccac0c44d..821fd427c8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ version: 1.0.0.{build} -image: Previous Visual Studio 2017 +image: Visual Studio 2017 # prevent the double build when a branch has an active PR skip_branch_with_pr: true diff --git a/build.ps1 b/build.ps1 index 35b8344dcc..215b551170 100644 --- a/build.ps1 +++ b/build.ps1 @@ -94,7 +94,7 @@ if("$env:APPVEYOR_API_URL" -ne ""){ } Write-Host "Building version '${version}'" -dotnet restore /p:packageversion=$version +dotnet restore /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true Write-Host "Building projects" dotnet build -c Release /p:packageversion=$version From 017cf581f630f6c04cc0bd6c85be7d83dc7d6c5f Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Sat, 1 Sep 2018 10:19:18 +0200 Subject: [PATCH 036/185] Added new issue templates. --- .github/ISSUE_TEMPLATE/ask-question.md | 13 +++++++++++++ .../bug-report.md} | 6 ++++++ .github/ISSUE_TEMPLATE/feature-request.md | 13 +++++++++++++ ImageSharp.sln | 4 +++- 4 files changed, 35 insertions(+), 1 deletion(-) create mode 100644 .github/ISSUE_TEMPLATE/ask-question.md rename .github/{ISSUE_TEMPLATE.md => ISSUE_TEMPLATE/bug-report.md} (93%) create mode 100644 .github/ISSUE_TEMPLATE/feature-request.md diff --git a/.github/ISSUE_TEMPLATE/ask-question.md b/.github/ISSUE_TEMPLATE/ask-question.md new file mode 100644 index 0000000000..c8313fba9f --- /dev/null +++ b/.github/ISSUE_TEMPLATE/ask-question.md @@ -0,0 +1,13 @@ +--- +name: Ask question +about: Ask a question about this project. + +--- + +You should not create an issue but use Gitter instead: https://gitter.im/ImageSharp/General + +You should not create an issue but use Gitter instead: https://gitter.im/ImageSharp/General + +You should not create an issue but use Gitter instead: https://gitter.im/ImageSharp/General + +You should not create an issue but use Gitter instead: https://gitter.im/ImageSharp/General \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE/bug-report.md similarity index 93% rename from .github/ISSUE_TEMPLATE.md rename to .github/ISSUE_TEMPLATE/bug-report.md index a172605e64..58a31246a9 100644 --- a/.github/ISSUE_TEMPLATE.md +++ b/.github/ISSUE_TEMPLATE/bug-report.md @@ -1,3 +1,9 @@ +--- +name: Bug report +about: Create a report to help us improve + +--- + ### Prerequisites - [ ] I have written a descriptive issue title diff --git a/.github/ISSUE_TEMPLATE/feature-request.md b/.github/ISSUE_TEMPLATE/feature-request.md new file mode 100644 index 0000000000..be1e593be4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.md @@ -0,0 +1,13 @@ +--- +name: Feature request +about: Suggest an idea for this project + +--- + +You should first discuss the feature on Gitter: https://gitter.im/ImageSharp/General + +You should first discuss the feature on Gitter: https://gitter.im/ImageSharp/General + +You should first discuss the feature on Gitter: https://gitter.im/ImageSharp/General + +You should first discuss the feature on Gitter: https://gitter.im/ImageSharp/General \ No newline at end of file diff --git a/ImageSharp.sln b/ImageSharp.sln index 0291d9f93a..8f3bc68602 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -8,13 +8,15 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "SolutionItems", "SolutionIt .editorconfig = .editorconfig .travis.yml = .travis.yml appveyor.yml = appveyor.yml + .github\ISSUE_TEMPLATE\ask-question.md = .github\ISSUE_TEMPLATE\ask-question.md + .github\ISSUE_TEMPLATE\bug-report.md = .github\ISSUE_TEMPLATE\bug-report.md codecov.yml = codecov.yml CodeCoverage.runsettings = CodeCoverage.runsettings .github\CONTRIBUTING.md = .github\CONTRIBUTING.md + .github\ISSUE_TEMPLATE\feature-request.md = .github\ISSUE_TEMPLATE\feature-request.md features.md = features.md ImageSharp.ruleset = ImageSharp.ruleset ImageSharp.sln.DotSettings = ImageSharp.sln.DotSettings - .github\ISSUE_TEMPLATE.md = .github\ISSUE_TEMPLATE.md NuGet.config = NuGet.config .github\PULL_REQUEST_TEMPLATE.md = .github\PULL_REQUEST_TEMPLATE.md README.md = README.md From aac48f7b59a01c628a59d5e3f2d881c2db000c7e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 1 Sep 2018 11:39:11 +0100 Subject: [PATCH 037/185] Add usings for clarity. --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index a420c07c8e..66dc0dcf43 100644 --- a/README.md +++ b/README.md @@ -70,6 +70,9 @@ Our API is designed to be simple to consume. Here's an example of the code requi On platforms supporting netstandard 1.3+ ```csharp +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; + // Image.Load(string path) is a shortcut for our default type. // Other pixel formats use Image.Load(string path)) using (Image image = Image.Load("foo.jpg")) @@ -83,6 +86,9 @@ using (Image image = Image.Load("foo.jpg")) On netstandard 1.1 - 1.2 ```csharp +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.Processing; + // Image.Load(Stream stream) is a shortcut for our default type. // Other pixel formats use Image.Load(Stream stream)) using (FileStream stream = File.OpenRead("foo.jpg")) @@ -99,6 +105,9 @@ using (Image image = Image.Load(stream)) Setting individual pixel values can be performed as follows: ```csharp +using SixLabors.ImageSharp; +using SixLabors.ImageSharp.PixelFormats; + // Individual pixels using (Image image = new Image(400, 400)) { From 7df8a4dda903e17f960f5eb78ef97d204547ede5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 1 Sep 2018 07:58:15 +0100 Subject: [PATCH 038/185] Fix appveyor build https://github.com/appveyor/ci/issues/2519#issuecomment-405828041 --- appveyor.yml | 2 +- build.ps1 | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index fccac0c44d..821fd427c8 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,5 +1,5 @@ version: 1.0.0.{build} -image: Previous Visual Studio 2017 +image: Visual Studio 2017 # prevent the double build when a branch has an active PR skip_branch_with_pr: true diff --git a/build.ps1 b/build.ps1 index 35b8344dcc..215b551170 100644 --- a/build.ps1 +++ b/build.ps1 @@ -94,7 +94,7 @@ if("$env:APPVEYOR_API_URL" -ne ""){ } Write-Host "Building version '${version}'" -dotnet restore /p:packageversion=$version +dotnet restore /p:packageversion=$version /p:DisableImplicitNuGetFallbackFolder=true Write-Host "Building projects" dotnet build -c Release /p:packageversion=$version From eec21fd89e17bfbeb22484a54c6dab9c98c98baf Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 3 Sep 2018 22:40:59 +0100 Subject: [PATCH 039/185] Add derived format info types and allow persistance of palette lengths --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 21 +++--- src/ImageSharp/Formats/Bmp/BmpInfo.cs | 25 +++++++ src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 57 ++++++++++----- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 30 +++++--- src/ImageSharp/Formats/Gif/GifInfo.cs | 33 +++++++++ .../Gif/Sections/GifImageDescriptor.cs | 2 +- .../Formats/Jpeg/JpegDecoderCore.cs | 7 +- src/ImageSharp/Formats/Jpeg/JpegInfo.cs | 25 +++++++ src/ImageSharp/Formats/Png/PngDecoderCore.cs | 8 +-- src/ImageSharp/Formats/Png/PngInfo.cs | 25 +++++++ src/ImageSharp/ImageInfo.cs | 12 ++-- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 13 ++-- .../Processors/Quantization/IQuantizer.cs | 9 +++ .../OctreeFrameQuantizer{TPixel}.cs | 32 +++++---- .../Quantization/OctreeQuantizer.cs | 23 ++++-- .../PaletteFrameQuantizer{TPixel}.cs | 2 + .../Quantization/PaletteQuantizer.cs | 20 ++++-- .../Quantization/WuFrameQuantizer{TPixel}.cs | 16 ++++- .../Processors/Quantization/WuQuantizer.cs | 21 ++++-- .../Formats/Gif/GifEncoderTests.cs | 39 +++++++++++ tests/ImageSharp.Tests/ImageInfoTests.cs | 70 ++++++++++++++++++- .../MetaData/ImageFrameMetaDataTests.cs | 21 ++++-- tests/ImageSharp.Tests/TestImages.cs | 3 +- .../ImageProviders/FileProvider.cs | 62 +++++++++------- .../SystemDrawingReferenceDecoder.cs | 11 ++- tests/Images/Input/Gif/leo.gif | 3 + 26 files changed, 466 insertions(+), 124 deletions(-) create mode 100644 src/ImageSharp/Formats/Bmp/BmpInfo.cs create mode 100644 src/ImageSharp/Formats/Gif/GifInfo.cs create mode 100644 src/ImageSharp/Formats/Jpeg/JpegInfo.cs create mode 100644 src/ImageSharp/Formats/Png/PngInfo.cs create mode 100644 tests/Images/Input/Gif/leo.gif diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index d67beb0368..4cb524ecb4 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Bmp { @@ -164,7 +165,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp public IImageInfo Identify(Stream stream) { this.ReadImageHeaders(stream, out _, out _); - return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), this.infoHeader.Width, this.infoHeader.Height, this.metaData); + + var size = new Size(this.infoHeader.Width, this.infoHeader.Height); + return new BmpInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), size, this.metaData); } /// @@ -175,10 +178,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// Whether the bitmap is inverted. /// The representing the inverted value. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int Invert(int y, int height, bool inverted) - { - return (!inverted) ? height - y - 1 : y; - } + private static int Invert(int y, int height, bool inverted) => (!inverted) ? height - y - 1 : y; /// /// Calculates the amount of bytes to pad a row. @@ -206,10 +206,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// The masked and shifted value /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte GetBytesFrom5BitValue(int value) - { - return (byte)((value << 3) | (value >> 2)); - } + private static byte GetBytesFrom5BitValue(int value) => (byte)((value << 3) | (value >> 2)); /// /// Looks up color values and builds the image from de-compressed RLE8 data. @@ -524,8 +521,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp } // Resolution is stored in PPM. - var meta = new ImageMetaData(); - meta.ResolutionUnits = PixelResolutionUnit.PixelsPerMeter; + var meta = new ImageMetaData + { + ResolutionUnits = PixelResolutionUnit.PixelsPerMeter + }; if (this.infoHeader.XPelsPerMeter > 0 && this.infoHeader.YPelsPerMeter > 0) { meta.HorizontalResolution = this.infoHeader.XPelsPerMeter; diff --git a/src/ImageSharp/Formats/Bmp/BmpInfo.cs b/src/ImageSharp/Formats/Bmp/BmpInfo.cs new file mode 100644 index 0000000000..dfffe94db7 --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpInfo.cs @@ -0,0 +1,25 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Formats.Bmp +{ + /// + /// Contains information about the bmp including dimensions, pixel type information and additional metadata. + /// + public class BmpInfo : ImageInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The image pixel type information. + /// The size of the image in pixels. + /// The images metadata. + internal BmpInfo(PixelTypeInfo pixelType, Size size, ImageMetaData metaData) + : base(pixelType, size, metaData) + { + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 2a4d981ebb..e791517521 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -55,6 +55,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// private GifGraphicControlExtension graphicsControlExtension; + /// + /// The image desciptor. + /// + private GifImageDescriptor imageDescriptor; + /// /// The metadata /// @@ -120,8 +125,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } else if (nextFlag == GifConstants.ExtensionIntroducer) { - int label = stream.ReadByte(); - switch (label) + switch (stream.ReadByte()) { case GifConstants.GraphicControlLabel: this.ReadGraphicalControlExtension(); @@ -178,13 +182,11 @@ namespace SixLabors.ImageSharp.Formats.Gif { if (nextFlag == GifConstants.ImageLabel) { - // Skip image block - this.Skip(0); + this.ReadImageDescriptor(); } else if (nextFlag == GifConstants.ExtensionIntroducer) { - int label = stream.ReadByte(); - switch (label) + switch (stream.ReadByte()) { case GifConstants.GraphicControlLabel: @@ -224,7 +226,17 @@ namespace SixLabors.ImageSharp.Formats.Gif this.globalColorTable?.Dispose(); } - return new ImageInfo(new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel), this.logicalScreenDescriptor.Width, this.logicalScreenDescriptor.Height, this.metaData); + GifColorTableMode colorTableMode = this.logicalScreenDescriptor.GlobalColorTableFlag + ? GifColorTableMode.Global + : GifColorTableMode.Local; + + var size = new Size(this.logicalScreenDescriptor.Width, this.logicalScreenDescriptor.Height); + + return new GifInfo( + colorTableMode, + new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel), + size, + this.metaData); } /// @@ -238,14 +250,13 @@ namespace SixLabors.ImageSharp.Formats.Gif } /// - /// Reads the image descriptor + /// Reads the image descriptor. /// - /// - private GifImageDescriptor ReadImageDescriptor() + private void ReadImageDescriptor() { this.stream.Read(this.buffer, 0, 9); - return GifImageDescriptor.Parse(this.buffer); + this.imageDescriptor = GifImageDescriptor.Parse(this.buffer); } /// @@ -312,25 +323,25 @@ namespace SixLabors.ImageSharp.Formats.Gif private void ReadFrame(ref Image image, ref ImageFrame previousFrame) where TPixel : struct, IPixel { - GifImageDescriptor imageDescriptor = this.ReadImageDescriptor(); + this.ReadImageDescriptor(); IManagedByteBuffer localColorTable = null; IManagedByteBuffer indices = null; try { // Determine the color table for this frame. If there is a local one, use it otherwise use the global color table. - if (imageDescriptor.LocalColorTableFlag) + if (this.imageDescriptor.LocalColorTableFlag) { - int length = imageDescriptor.LocalColorTableSize * 3; + int length = this.imageDescriptor.LocalColorTableSize * 3; localColorTable = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(length, AllocationOptions.Clean); this.stream.Read(localColorTable.Array, 0, length); } - indices = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(imageDescriptor.Width * imageDescriptor.Height, AllocationOptions.Clean); + indices = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(this.imageDescriptor.Width * this.imageDescriptor.Height, AllocationOptions.Clean); - this.ReadFrameIndices(imageDescriptor, indices.GetSpan()); + this.ReadFrameIndices(this.imageDescriptor, indices.GetSpan()); ReadOnlySpan colorTable = MemoryMarshal.Cast((localColorTable ?? this.globalColorTable).GetSpan()); - this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, imageDescriptor); + this.ReadFrameColors(ref image, ref previousFrame, indices.GetSpan(), colorTable, this.imageDescriptor); // Skip any remaining blocks this.Skip(0); @@ -508,6 +519,18 @@ namespace SixLabors.ImageSharp.Formats.Gif meta.FrameDelay = this.graphicsControlExtension.DelayTime; } + // Frames can either use the global table or their own local table. + if (this.logicalScreenDescriptor.GlobalColorTableFlag + && this.logicalScreenDescriptor.GlobalColorTableSize > 0) + { + meta.ColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize; + } + else if (this.imageDescriptor.LocalColorTableFlag + && this.imageDescriptor.LocalColorTableSize > 0) + { + meta.ColorTableLength = this.imageDescriptor.LocalColorTableSize; + } + meta.DisposalMethod = this.graphicsControlExtension.DisposalMethod; } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 5532900355..ab0ee1fb6f 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -146,7 +146,8 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - using (QuantizedFrame paletteQuantized = palleteQuantizer.CreateFrameQuantizer(() => quantized.Palette).QuantizeFrame(frame)) + using (QuantizedFrame paletteQuantized + = palleteQuantizer.CreateFrameQuantizer(() => quantized.Palette).QuantizeFrame(frame)) { this.WriteImageData(paletteQuantized, stream); } @@ -157,13 +158,25 @@ namespace SixLabors.ImageSharp.Formats.Gif private void EncodeLocal(Image image, QuantizedFrame quantized, Stream stream) where TPixel : struct, IPixel { + ImageFrame previousFrame = null; foreach (ImageFrame frame in image.Frames) { if (quantized is null) { - quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + // Allow each frame to be encoded at whatever color depth the frame designates if set. + if (previousFrame != null + && previousFrame.MetaData.ColorTableLength != frame.MetaData.ColorTableLength + && frame.MetaData.ColorTableLength > 0) + { + quantized = this.quantizer.CreateFrameQuantizer(frame.MetaData.ColorTableLength).QuantizeFrame(frame); + } + else + { + quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(frame); + } } + this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); this.WriteGraphicalControlExtension(frame.MetaData, this.GetTransparentIndex(quantized), stream); this.WriteImageDescriptor(frame, true, stream); this.WriteColorTable(quantized, stream); @@ -171,6 +184,7 @@ namespace SixLabors.ImageSharp.Formats.Gif quantized?.Dispose(); quantized = null; // So next frame can regenerate it + previousFrame = frame; } } @@ -210,10 +224,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The stream to write to. [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void WriteHeader(Stream stream) - { - stream.Write(GifConstants.MagicNumber, 0, GifConstants.MagicNumber.Length); - } + private void WriteHeader(Stream stream) => stream.Write(GifConstants.MagicNumber, 0, GifConstants.MagicNumber.Length); /// /// Writes the logical screen descriptor to the stream. @@ -226,7 +237,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteLogicalScreenDescriptor(Image image, int transparencyIndex, bool useGlobalTable, Stream stream) where TPixel : struct, IPixel { - byte packedValue = GifLogicalScreenDescriptor.GetPackedValue(useGlobalTable, this.bitDepth - 1, false, this.bitDepth - 1); + byte packedValue = GifLogicalScreenDescriptor.GetPackedValue(useGlobalTable, this.bitDepth, false, this.bitDepth - 1); // The Pixel Aspect Ratio is defined to be the quotient of the pixel's // width over its height. The value range in this field allows @@ -382,7 +393,7 @@ namespace SixLabors.ImageSharp.Formats.Gif localColorTableFlag: hasColorTable, interfaceFlag: false, sortFlag: false, - localColorTableSize: (byte)this.bitDepth); + localColorTableSize: this.bitDepth - 1); var descriptor = new GifImageDescriptor( left: 0, @@ -407,7 +418,8 @@ namespace SixLabors.ImageSharp.Formats.Gif { int pixelCount = image.Palette.Length; - int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3; // The maximium number of colors for the bit depth + // The maximium number of colors for the bit depth + int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3; Rgb24 rgb = default; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) diff --git a/src/ImageSharp/Formats/Gif/GifInfo.cs b/src/ImageSharp/Formats/Gif/GifInfo.cs new file mode 100644 index 0000000000..1c345a576b --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifInfo.cs @@ -0,0 +1,33 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Formats.Gif +{ + /// + /// Contains information about the bmp including dimensions, pixel type information and additional metadata. + /// + public class GifInfo : ImageInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The color table mode. + /// The image pixel type information. + /// The size of the image in pixels. + /// The images metadata. + internal GifInfo( + GifColorTableMode colorTableMode, + PixelTypeInfo pixelType, + Size size, + ImageMetaData metaData) + : base(pixelType, size, metaData) => this.ColorTableMode = colorTableMode; + + /// + /// Gets the color table mode. + /// + public GifColorTableMode ColorTableMode { get; } + } +} diff --git a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs index c5360729e8..e2f5bee78e 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs +++ b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.Formats.Gif return MemoryMarshal.Cast(buffer)[0]; } - public static byte GetPackedValue(bool localColorTableFlag, bool interfaceFlag, bool sortFlag, byte localColorTableSize) + public static byte GetPackedValue(bool localColorTableFlag, bool interfaceFlag, bool sortFlag, int localColorTableSize) { /* Local Color Table Flag | 1 Bit diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 7561afa1ef..fb717d3fb8 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -234,7 +234,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.InitExifProfile(); this.InitIccProfile(); this.InitDerivedMetaDataProperties(); - return new ImageInfo(new PixelTypeInfo(this.BitsPerPixel), this.ImageWidth, this.ImageHeight, this.MetaData); + + return new JpegInfo(new PixelTypeInfo(this.BitsPerPixel), new Size(this.ImageWidth, this.ImageHeight), this.MetaData); } /// @@ -899,9 +900,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The values [MethodImpl(MethodImplOptions.AggressiveInlining)] private void BuildHuffmanTable(HuffmanTables tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) - { - tables[index] = new HuffmanTable(this.configuration.MemoryAllocator, codeLengths, values); - } + => tables[index] = new HuffmanTable(this.configuration.MemoryAllocator, codeLengths, values); /// /// Reads a from the stream advancing it by two bytes diff --git a/src/ImageSharp/Formats/Jpeg/JpegInfo.cs b/src/ImageSharp/Formats/Jpeg/JpegInfo.cs new file mode 100644 index 0000000000..8e9b6257c3 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegInfo.cs @@ -0,0 +1,25 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Formats.Jpeg +{ + /// + /// Contains information about the bmp including dimensions, pixel type information and additional metadata. + /// + public class JpegInfo : ImageInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The image pixel type information. + /// The size of the image in pixels. + /// The images metadata. + internal JpegInfo(PixelTypeInfo pixelType, Size size, ImageMetaData metaData) + : base(pixelType, size, metaData) + { + } + } +} diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index aa96b926ca..9032560160 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -10,7 +10,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Memory; @@ -18,6 +17,7 @@ using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Png { @@ -349,7 +349,7 @@ namespace SixLabors.ImageSharp.Formats.Png throw new ImageFormatException("PNG Image does not contain a header chunk"); } - return new ImageInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), this.header.Width, this.header.Height, metadata); + return new PngInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), new Size(this.header.Width, this.header.Height), metadata); } /// @@ -360,9 +360,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] private static byte ReadByteLittleEndian(ReadOnlySpan buffer, int offset) - { - return (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); - } + => (byte)(((buffer[offset] & 0xFF) << 16) | (buffer[offset + 1] & 0xFF)); /// /// Attempts to convert a byte array to a new array where each value in the original array is represented by the diff --git a/src/ImageSharp/Formats/Png/PngInfo.cs b/src/ImageSharp/Formats/Png/PngInfo.cs new file mode 100644 index 0000000000..2bb0b16b70 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngInfo.cs @@ -0,0 +1,25 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Formats.Png +{ + /// + /// Contains information about the bmp including dimensions, pixel type information and additional metadata. + /// + public class PngInfo : ImageInfo + { + /// + /// Initializes a new instance of the class. + /// + /// The image pixel type information. + /// The size of the image in pixels. + /// The images metadata. + internal PngInfo(PixelTypeInfo pixelType, Size size, ImageMetaData metaData) + : base(pixelType, size, metaData) + { + } + } +} diff --git a/src/ImageSharp/ImageInfo.cs b/src/ImageSharp/ImageInfo.cs index 6f894cb599..eed1c66918 100644 --- a/src/ImageSharp/ImageInfo.cs +++ b/src/ImageSharp/ImageInfo.cs @@ -3,26 +3,26 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData; +using SixLabors.Primitives; namespace SixLabors.ImageSharp { /// /// Contains information about the image including dimensions, pixel type information and additional metadata /// - internal sealed class ImageInfo : IImageInfo + public abstract class ImageInfo : IImageInfo { /// /// Initializes a new instance of the class. /// /// The image pixel type information. - /// The width of the image in pixels. - /// The height of the image in pixels. + /// The size of the image in pixels. /// The images metadata. - public ImageInfo(PixelTypeInfo pixelType, int width, int height, ImageMetaData metaData) + protected ImageInfo(PixelTypeInfo pixelType, Size size, ImageMetaData metaData) { this.PixelType = pixelType; - this.Width = width; - this.Height = height; + this.Width = size.Width; + this.Height = size.Height; this.MetaData = metaData; } diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 47a2fb775f..f83e092c9f 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -28,10 +28,18 @@ namespace SixLabors.ImageSharp.MetaData { DebugGuard.NotNull(other, nameof(other)); + this.ColorTableLength = other.ColorTableLength; this.FrameDelay = other.FrameDelay; this.DisposalMethod = other.DisposalMethod; } + /// + /// Gets or sets the length of the color table for paletted images. + /// If not 0, then this field indicates the maximum number of colors to use when quantizing the + /// image frame. + /// + public int ColorTableLength { get; set; } + /// /// Gets or sets the frame delay for animated images. /// If not 0, when utilized in Gif animation, this field specifies the number of hundredths (1/100) of a second to @@ -51,9 +59,6 @@ namespace SixLabors.ImageSharp.MetaData /// Clones this ImageFrameMetaData. /// /// The cloned instance. - public ImageFrameMetaData Clone() - { - return new ImageFrameMetaData(this); - } + public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs index 0f6846d1bf..3da09cde09 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/IQuantizer.cs @@ -23,5 +23,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The IFrameQuantizer CreateFrameQuantizer() where TPixel : struct, IPixel; + + /// + /// Creates the generic frame quantizer + /// + /// The pixel format. + /// The maximum number of colors to hold in the color palette. + /// The + IFrameQuantizer CreateFrameQuantizer(int maxColors) + where TPixel : struct, IPixel; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs index 3eac70eea5..39546d63f7 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeFrameQuantizer{TPixel}.cs @@ -22,7 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Maximum allowed color depth /// - private readonly byte colors; + private readonly int colors; /// /// Stores the tree @@ -43,9 +43,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// the second pass quantizes a color based on the nodes in the tree /// public OctreeFrameQuantizer(OctreeQuantizer quantizer) + : this(quantizer, quantizer.MaxColors) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The octree quantizer. + /// The maximum number of colors to hold in the color palette. + /// + /// The Octree quantizer is a two pass algorithm. The initial pass sets up the Octree, + /// the second pass quantizes a color based on the nodes in the tree + /// + public OctreeFrameQuantizer(OctreeQuantizer quantizer, int maxColors) : base(quantizer, false) { - this.colors = (byte)quantizer.MaxColors; + this.colors = maxColors; this.octree = new Octree(ImageMaths.GetBitsNeededForColorDepth(this.colors).Clamp(1, 8)); } @@ -261,13 +275,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization [MethodImpl(MethodImplOptions.AggressiveInlining)] public TPixel[] Palletize(int colorCount) { - while (this.Leaves > colorCount) + while (this.Leaves > colorCount - 1) { this.Reduce(); } // Now palletize the nodes - var palette = new TPixel[colorCount + 1]; + var palette = new TPixel[colorCount]; int paletteIndex = 0; this.root.ConstructPalette(palette, ref paletteIndex); @@ -285,10 +299,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public int GetPaletteIndex(ref TPixel pixel, ref Rgba32 rgba) - { - return this.root.GetPaletteIndex(ref pixel, 0, ref rgba); - } + public int GetPaletteIndex(ref TPixel pixel, ref Rgba32 rgba) => this.root.GetPaletteIndex(ref pixel, 0, ref rgba); /// /// Keep track of the previous node that was quantized @@ -297,10 +308,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The node last quantized /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - protected void TrackPrevious(OctreeNode node) - { - this.previousNode = node; - } + protected void TrackPrevious(OctreeNode node) => this.previousNode = node; /// /// Reduce the depth of the tree diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs index 385f6246f8..22bb5223f0 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer.cs @@ -15,6 +15,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class OctreeQuantizer : IQuantizer { + /// + /// The default maximum number of colors to use when quantizing the image. + /// + public const int DefaultMaxColors = 256; + /// /// Initializes a new instance of the class. /// @@ -26,7 +31,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Initializes a new instance of the class. /// - /// The maximum number of colors to hold in the color palette + /// The maximum number of colors to hold in the color palette. public OctreeQuantizer(int maxColors) : this(GetDiffuser(true), maxColors) { @@ -37,7 +42,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Whether to apply dithering to the output image public OctreeQuantizer(bool dither) - : this(GetDiffuser(dither), 255) + : this(GetDiffuser(dither), DefaultMaxColors) { } @@ -46,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The error diffusion algorithm, if any, to apply to the output image public OctreeQuantizer(IErrorDiffuser diffuser) - : this(diffuser, 255) + : this(diffuser, DefaultMaxColors) { } @@ -57,10 +62,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The maximum number of colors to hold in the color palette public OctreeQuantizer(IErrorDiffuser diffuser, int maxColors) { - Guard.MustBeBetweenOrEqualTo(maxColors, 1, 255, nameof(maxColors)); - this.Diffuser = diffuser; - this.MaxColors = maxColors; + this.MaxColors = maxColors.Clamp(1, DefaultMaxColors); } /// @@ -76,6 +79,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization where TPixel : struct, IPixel => new OctreeFrameQuantizer(this); + /// + public IFrameQuantizer CreateFrameQuantizer(int maxColors) + where TPixel : struct, IPixel + { + maxColors = maxColors.Clamp(1, DefaultMaxColors); + return new OctreeFrameQuantizer(this, maxColors); + } + private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs index 8df81b426f..cdf3514e2d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteFrameQuantizer{TPixel}.cs @@ -36,6 +36,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization public PaletteFrameQuantizer(PaletteQuantizer quantizer, TPixel[] colors) : base(quantizer, true) { + // TODO: Why is this value constrained? Gif has limitations but theoretically + // we might want to reduce the palette of an image to greater than that limitation. Guard.MustBeBetweenOrEqualTo(colors.Length, 1, 256, nameof(colors)); this.palette = colors; this.paletteVector = new Vector4[this.palette.Length]; diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs index 8ae9177185..27ef05dfe9 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer.cs @@ -37,10 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Initializes a new instance of the class. /// /// The error diffusion algorithm, if any, to apply to the output image - public PaletteQuantizer(IErrorDiffuser diffuser) - { - this.Diffuser = diffuser; - } + public PaletteQuantizer(IErrorDiffuser diffuser) => this.Diffuser = diffuser; /// public IErrorDiffuser Diffuser { get; } @@ -50,6 +47,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization where TPixel : struct, IPixel => this.CreateFrameQuantizer(() => NamedColors.WebSafePalette); + /// + public IFrameQuantizer CreateFrameQuantizer(int maxColors) + where TPixel : struct, IPixel + { + TPixel[] websafe = NamedColors.WebSafePalette; + int max = Math.Min(maxColors, websafe.Length); + + if (max != websafe.Length) + { + return this.CreateFrameQuantizer(() => NamedColors.WebSafePalette.AsSpan(0, max).ToArray()); + } + + return this.CreateFrameQuantizer(() => websafe); + } + /// /// Gets the palette to use to quantize the image. /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 021dc62fbf..d71221b9d6 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -3,7 +3,6 @@ using System; using System.Buffers; -using System.Collections.Generic; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -128,11 +127,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// the second pass quantizes a color based on the position in the histogram. /// public WuFrameQuantizer(WuQuantizer quantizer) - : base(quantizer, false) + : this(quantizer, quantizer.MaxColors) { - this.colors = quantizer.MaxColors; } + /// + /// Initializes a new instance of the class. + /// + /// The wu quantizer. + /// The maximum number of colors to hold in the color palette. + /// + /// The Wu quantizer is a two pass algorithm. The initial pass sets up the 3-D color histogram, + /// the second pass quantizes a color based on the position in the histogram. + /// + public WuFrameQuantizer(WuQuantizer quantizer, int maxColors) + : base(quantizer, false) => this.colors = maxColors; + /// public override QuantizedFrame QuantizeFrame(ImageFrame image) { diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs index 3aa1f4c5e6..5123e737d3 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer.cs @@ -14,6 +14,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// public class WuQuantizer : IQuantizer { + /// + /// The default maximum number of colors to use when quantizing the image. + /// + public const int DefaultMaxColors = 256; + /// /// Initializes a new instance of the class. /// @@ -36,7 +41,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// Whether to apply dithering to the output image public WuQuantizer(bool dither) - : this(GetDiffuser(dither), 255) + : this(GetDiffuser(dither), DefaultMaxColors) { } @@ -45,7 +50,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The error diffusion algorithm, if any, to apply to the output image public WuQuantizer(IErrorDiffuser diffuser) - : this(diffuser, 255) + : this(diffuser, DefaultMaxColors) { } @@ -56,10 +61,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The maximum number of colors to hold in the color palette public WuQuantizer(IErrorDiffuser diffuser, int maxColors) { - Guard.MustBeBetweenOrEqualTo(maxColors, 1, 255, nameof(maxColors)); - this.Diffuser = diffuser; - this.MaxColors = maxColors; + this.MaxColors = maxColors.Clamp(1, DefaultMaxColors); } /// @@ -75,6 +78,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization where TPixel : struct, IPixel => new WuFrameQuantizer(this); + /// + public IFrameQuantizer CreateFrameQuantizer(int maxColors) + where TPixel : struct, IPixel + { + maxColors = maxColors.Clamp(1, DefaultMaxColors); + return new WuFrameQuantizer(this, maxColors); + } + private static IErrorDiffuser GetDiffuser(bool dither) => dither ? KnownDiffusers.FloydSteinberg : null; } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index e9104ef8d9..11fa4d5d5f 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -179,5 +179,44 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif Assert.True(fileInfoGlobal.Length < fileInfoLocal.Length); } } + + [Fact] + public void NonMutatingEncodePreservesPaletteCount() + { + using (var inStream = new MemoryStream(TestFile.Create(TestImages.Gif.Leo).Bytes)) + using (var outStream = new MemoryStream()) + { + var info = (GifInfo)Image.Identify(inStream); + GifColorTableMode colorMode = info.ColorTableMode; + inStream.Position = 0; + + var image = Image.Load(inStream); + var encoder = new GifEncoder() + { + ColorTableMode = colorMode, + Quantizer = new OctreeQuantizer(image.Frames.RootFrame.MetaData.ColorTableLength) + }; + + image.Save(outStream, encoder); + outStream.Position = 0; + + var cloneInfo = (GifInfo)Image.Identify(outStream); + outStream.Position = 0; + var clone = Image.Load(outStream); + + // Gifiddle and Cyotek GifInfo say this image has 64 colors. + Assert.Equal(64, image.Frames.RootFrame.MetaData.ColorTableLength); + Assert.Equal(info.ColorTableMode, cloneInfo.ColorTableMode); + + for (int i = 0; i < image.Frames.Count; i++) + { + Assert.Equal(image.Frames[i].MetaData.ColorTableLength, clone.Frames[i].MetaData.ColorTableLength); + Assert.Equal(image.Frames[i].MetaData.FrameDelay, clone.Frames[i].MetaData.FrameDelay); + } + + image.Dispose(); + clone.Dispose(); + } + } } } diff --git a/tests/ImageSharp.Tests/ImageInfoTests.cs b/tests/ImageSharp.Tests/ImageInfoTests.cs index 91f6804c0f..d46e340521 100644 --- a/tests/ImageSharp.Tests/ImageInfoTests.cs +++ b/tests/ImageSharp.Tests/ImageInfoTests.cs @@ -2,6 +2,10 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Bmp; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.MetaData; using SixLabors.Primitives; @@ -12,7 +16,7 @@ namespace SixLabors.ImageSharp.Tests public class ImageInfoTests { [Fact] - public void ImageInfoInitializesCorrectly() + public void JpegInfoInitializesCorrectly() { const int Width = 50; const int Height = 60; @@ -21,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests var pixelType = new PixelTypeInfo(8); var meta = new ImageMetaData(); - var info = new ImageInfo(pixelType, Width, Height, meta); + var info = new JpegInfo(pixelType, size, meta); Assert.Equal(pixelType, info.PixelType); Assert.Equal(Width, info.Width); @@ -30,5 +34,67 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(rectangle, info.Bounds()); Assert.Equal(meta, info.MetaData); } + + [Fact] + public void BmpInfoInitializesCorrectly() + { + const int Width = 50; + const int Height = 60; + var size = new Size(Width, Height); + var rectangle = new Rectangle(0, 0, Width, Height); + var pixelType = new PixelTypeInfo(8); + var meta = new ImageMetaData(); + + var info = new BmpInfo(pixelType, size, meta); + + Assert.Equal(pixelType, info.PixelType); + Assert.Equal(Width, info.Width); + Assert.Equal(Height, info.Height); + Assert.Equal(size, info.Size()); + Assert.Equal(rectangle, info.Bounds()); + Assert.Equal(meta, info.MetaData); + } + + [Fact] + public void PngInfoInitializesCorrectly() + { + const int Width = 50; + const int Height = 60; + var size = new Size(Width, Height); + var rectangle = new Rectangle(0, 0, Width, Height); + var pixelType = new PixelTypeInfo(8); + var meta = new ImageMetaData(); + + var info = new PngInfo(pixelType, size, meta); + + Assert.Equal(pixelType, info.PixelType); + Assert.Equal(Width, info.Width); + Assert.Equal(Height, info.Height); + Assert.Equal(size, info.Size()); + Assert.Equal(rectangle, info.Bounds()); + Assert.Equal(meta, info.MetaData); + } + + [Fact] + public void GifInfoInitializesCorrectly() + { + const GifColorTableMode mode = GifColorTableMode.Local; + const int Width = 50; + const int Height = 60; + var size = new Size(Width, Height); + var rectangle = new Rectangle(0, 0, Width, Height); + var pixelType = new PixelTypeInfo(8); + var meta = new ImageMetaData(); + + var info = new GifInfo(mode, pixelType, size, meta); + + Assert.Equal(mode, info.ColorTableMode); + Assert.Equal(pixelType, info.PixelType); + Assert.Equal(Width, info.Width); + Assert.Equal(Height, info.Height); + Assert.Equal(size, info.Size()); + Assert.Equal(rectangle, info.Bounds()); + Assert.Equal(meta, info.MetaData); + } } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 507401398e..6e18fe2537 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.MetaData; using Xunit; @@ -16,14 +15,22 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ConstructorImageFrameMetaData() { - ImageFrameMetaData metaData = new ImageFrameMetaData(); - metaData.FrameDelay = 42; - metaData.DisposalMethod = DisposalMethod.RestoreToBackground; + const int frameDelay = 42; + const int colorTableLength = 128; + const DisposalMethod disposalMethod = DisposalMethod.RestoreToBackground; - ImageFrameMetaData clone = new ImageFrameMetaData(metaData); + var metaData = new ImageFrameMetaData + { + FrameDelay = frameDelay, + ColorTableLength = colorTableLength, + DisposalMethod = disposalMethod + }; - Assert.Equal(42, clone.FrameDelay); - Assert.Equal(DisposalMethod.RestoreToBackground, clone.DisposalMethod); + var clone = new ImageFrameMetaData(metaData); + + Assert.Equal(frameDelay, clone.FrameDelay); + Assert.Equal(colorTableLength, clone.ColorTableLength); + Assert.Equal(disposalMethod, clone.DisposalMethod); } } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1ee3f96757..7a82a618cb 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -201,6 +201,7 @@ namespace SixLabors.ImageSharp.Tests public const string Cheers = "Gif/cheers.gif"; public const string Trans = "Gif/trans.gif"; public const string Kumin = "Gif/kumin.gif"; + public const string Leo = "Gif/leo.gif"; public const string Ratio4x1 = "Gif/base_4x1.gif"; public const string Ratio1x4 = "Gif/base_1x4.gif"; @@ -211,7 +212,7 @@ namespace SixLabors.ImageSharp.Tests public const string BadDescriptorWidth = "Gif/issues/issue403_baddescriptorwidth.gif"; } - public static readonly string[] All = { Rings, Giphy, Cheers, Trans, Kumin, Ratio4x1, Ratio1x4 }; + public static readonly string[] All = { Rings, Giphy, Cheers, Trans, Kumin, Leo, Ratio4x1, Ratio1x4 }; } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs index 6475547a06..3ed696c472 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/FileProvider.cs @@ -55,9 +55,20 @@ namespace SixLabors.ImageSharp.Tests public bool Equals(Key other) { - if (other is null) return false; - if (ReferenceEquals(this, other)) return true; - if (!this.commonValues.Equals(other.commonValues)) return false; + if (other is null) + { + return false; + } + + if (ReferenceEquals(this, other)) + { + return true; + } + + if (!this.commonValues.Equals(other.commonValues)) + { + return false; + } if (this.decoderParameters.Count != other.decoderParameters.Count) { @@ -66,8 +77,7 @@ namespace SixLabors.ImageSharp.Tests foreach (KeyValuePair kv in this.decoderParameters) { - object otherVal; - if (!other.decoderParameters.TryGetValue(kv.Key, out otherVal)) + if (!other.decoderParameters.TryGetValue(kv.Key, out object otherVal)) { return false; } @@ -81,26 +91,29 @@ namespace SixLabors.ImageSharp.Tests public override bool Equals(object obj) { - if (obj is null) return false; - if (ReferenceEquals(this, obj)) return true; - if (obj.GetType() != this.GetType()) return false; + if (obj is null) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj.GetType() != this.GetType()) + { + return false; + } + return this.Equals((Key)obj); } - public override int GetHashCode() - { - return this.commonValues.GetHashCode(); - } + public override int GetHashCode() => this.commonValues.GetHashCode(); - public static bool operator ==(Key left, Key right) - { - return Equals(left, right); - } + public static bool operator ==(Key left, Key right) => Equals(left, right); - public static bool operator !=(Key left, Key right) - { - return !Equals(left, right); - } + public static bool operator !=(Key left, Key right) => !Equals(left, right); } private static readonly ConcurrentDictionary> cache = new ConcurrentDictionary>(); @@ -111,10 +124,7 @@ namespace SixLabors.ImageSharp.Tests { } - public FileProvider(string filePath) - { - this.FilePath = filePath; - } + public FileProvider(string filePath) => this.FilePath = filePath; /// /// Gets the file path relative to the "~/tests/images" folder @@ -135,12 +145,12 @@ namespace SixLabors.ImageSharp.Tests if (!TestEnvironment.Is64BitProcess) { - return LoadImage(decoder); + return this.LoadImage(decoder); } var key = new Key(this.PixelType, this.FilePath, decoder); - Image cachedImage = cache.GetOrAdd(key, fn => { return LoadImage(decoder); }); + Image cachedImage = cache.GetOrAdd(key, _ => this.LoadImage(decoder)); return cachedImage.Clone(); } diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs index 427a565424..3696accdd3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs @@ -48,7 +48,16 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs using (var sourceBitmap = new System.Drawing.Bitmap(stream)) { var pixelType = new PixelTypeInfo(System.Drawing.Image.GetPixelFormatSize(sourceBitmap.PixelFormat)); - return new ImageInfo(pixelType, sourceBitmap.Width, sourceBitmap.Height, new ImageMetaData()); + var size = new SixLabors.Primitives.Size(sourceBitmap.Width, sourceBitmap.Height); + return new SystemDrawingInfo(pixelType, size, new ImageMetaData()); + } + } + + private class SystemDrawingInfo : ImageInfo + { + public SystemDrawingInfo(PixelTypeInfo pixelType, SixLabors.Primitives.Size size, ImageMetaData metaData) + : base(pixelType, size, metaData) + { } } } diff --git a/tests/Images/Input/Gif/leo.gif b/tests/Images/Input/Gif/leo.gif new file mode 100644 index 0000000000..8cf7078380 --- /dev/null +++ b/tests/Images/Input/Gif/leo.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:6ee2bf4404165d534dcbfaebece0eee2a93999c47aec26850a7021b8c5d25f5c +size 454544 From 74aff0ea06ee21b26a499bb1bc4e55cc273fc32d Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Tue, 4 Sep 2018 23:53:07 +0200 Subject: [PATCH 040/185] Adding more tests to cover single pixel ColorBlending and AlphaComposition functions --- .../PixelOperationsTests.Blender.cs | 58 ++++++++++++++++++- 1 file changed, 57 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs index 8f574ca169..3c562057a8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperationsTests.Blender.cs @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { new TestPixel(), typeof(DefaultPixelBlenders.AddSrcOver), PixelColorBlendingMode.Add }, { new TestPixel(), typeof(DefaultPixelBlenders.SubtractSrcOver), PixelColorBlendingMode.Subtract }, { new TestPixel(), typeof(DefaultPixelBlenders.MultiplySrcOver), PixelColorBlendingMode.Multiply }, - }; + }; [Theory] [MemberData(nameof(BlenderMappings))] @@ -43,6 +43,62 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats { PixelBlender blender = PixelOperations.Instance.GetPixelBlender(mode, PixelAlphaCompositionMode.SrcOver); Assert.IsType(type, blender); + } + + public static TheoryData ColorBlendingExpectedResults = new TheoryData() + { + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelColorBlendingMode.Normal, Rgba32.MidnightBlue }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelColorBlendingMode.Screen, new Rgba32(0xFFEEE7FF) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelColorBlendingMode.HardLight, new Rgba32(0xFFC62D32) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelColorBlendingMode.Overlay, new Rgba32(0xFFDDCEFF) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelColorBlendingMode.Darken, new Rgba32(0xFF701919) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelColorBlendingMode.Lighten, new Rgba32(0xFFE1E4FF) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelColorBlendingMode.Add, new Rgba32(0xFFFFFDFF) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelColorBlendingMode.Subtract, new Rgba32(0xFF71CBE6) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelColorBlendingMode.Multiply, new Rgba32(0xFF631619) }, + + }; + + [Theory] + [MemberData(nameof(ColorBlendingExpectedResults))] + public void TestColorBlendingModes(Rgba32 backdrop, Rgba32 source, float opacity, PixelColorBlendingMode mode, Rgba32 expectedResult) + { + PixelBlender blender = PixelOperations.Instance.GetPixelBlender(mode, PixelAlphaCompositionMode.SrcOver); + + Rgba32 actualResult = blender.Blend(backdrop, source, opacity); + + // var str = actualResult.Rgba.ToString("X8"); // used to extract expectedResults + + Assert.Equal(actualResult.ToVector4(), expectedResult.ToVector4()); + } + + public static TheoryData AlphaCompositionExpectedResults = new TheoryData() + { + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.Clear, new Rgba32(0) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.Xor, new Rgba32(0) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.Dest, Rgba32.MistyRose }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.DestAtop, Rgba32.MistyRose }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.DestIn, Rgba32.MistyRose }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.DestOut, new Rgba32(0) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.DestOver, Rgba32.MistyRose }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.Src, Rgba32.MidnightBlue }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.SrcAtop, Rgba32.MidnightBlue }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.SrcIn, Rgba32.MidnightBlue }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.SrcOut, new Rgba32(0) }, + { Rgba32.MistyRose, Rgba32.MidnightBlue, 1, PixelAlphaCompositionMode.SrcOver, Rgba32.MidnightBlue }, + }; + + [Theory] + [MemberData(nameof(AlphaCompositionExpectedResults))] + public void TestAlphaCompositionModes(Rgba32 backdrop, Rgba32 source, float opacity, PixelAlphaCompositionMode mode, Rgba32 expectedResult) + { + PixelBlender blender = PixelOperations.Instance.GetPixelBlender(PixelColorBlendingMode.Normal, mode); + + Rgba32 actualResult = blender.Blend(backdrop, source, opacity); + + // var str = actualResult.Rgba.ToString("X8"); // used to extract expectedResults + + Assert.Equal(actualResult.ToVector4(), expectedResult.ToVector4()); } } } From 3644451e6d5d6d53d58506c75a160ed445e01d46 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 5 Sep 2018 20:07:19 +0100 Subject: [PATCH 041/185] Use dictionaries to store format specific metadata --- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 5 +- src/ImageSharp/Formats/Bmp/BmpInfo.cs | 25 ------ .../Formats/Gif/GifColorTableMode.cs | 2 +- src/ImageSharp/Formats/Gif/GifConstants.cs | 18 +++- src/ImageSharp/Formats/Gif/GifDecoder.cs | 1 + src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 89 +++++++++++++------ ...DisposalMethod.cs => GifDisposalMethod.cs} | 2 +- src/ImageSharp/Formats/Gif/GifEncoder.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 54 +++++------ .../Formats/Gif/GifFrameMetaData.cs | 33 +++++++ src/ImageSharp/Formats/Gif/GifInfo.cs | 33 ------- src/ImageSharp/Formats/Gif/GifMetaData.cs | 29 ++++++ .../Formats/Gif/GifMetaDataExtensions.cs | 49 ++++++++++ .../Formats/Gif/IGifDecoderOptions.cs | 1 + .../Formats/Gif/IGifEncoderOptions.cs | 2 +- .../Sections/GifGraphicControlExtension.cs | 4 +- .../GifNetscapeLoopingApplicationExtension.cs | 44 +++++++++ .../Formats/Jpeg/JpegDecoderCore.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegInfo.cs | 25 ------ src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 +- src/ImageSharp/Formats/Png/PngInfo.cs | 25 ------ src/ImageSharp/ImageInfo.cs | 12 +-- .../Gif => MetaData}/FrameDecodingMode.cs | 2 +- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 67 +++++++++----- src/ImageSharp/MetaData/ImageMetaData.cs | 69 ++++++++++---- .../Formats/Gif/GifEncoderTests.cs | 21 +++-- .../GifGraphicControlExtensionTests.cs | 8 +- tests/ImageSharp.Tests/ImageInfoTests.cs | 70 +-------------- .../MetaData/ImageFrameMetaDataTests.cs | 14 +-- .../MetaData/ImageMetaDataTests.cs | 2 - .../SystemDrawingReferenceDecoder.cs | 11 +-- 31 files changed, 399 insertions(+), 325 deletions(-) delete mode 100644 src/ImageSharp/Formats/Bmp/BmpInfo.cs rename src/ImageSharp/Formats/Gif/{DisposalMethod.cs => GifDisposalMethod.cs} (97%) create mode 100644 src/ImageSharp/Formats/Gif/GifFrameMetaData.cs delete mode 100644 src/ImageSharp/Formats/Gif/GifInfo.cs create mode 100644 src/ImageSharp/Formats/Gif/GifMetaData.cs create mode 100644 src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs create mode 100644 src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/JpegInfo.cs delete mode 100644 src/ImageSharp/Formats/Png/PngInfo.cs rename src/ImageSharp/{Formats/Gif => MetaData}/FrameDecodingMode.cs (91%) diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 4cb524ecb4..385c79896e 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -10,7 +10,6 @@ using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; -using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Bmp { @@ -165,9 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp public IImageInfo Identify(Stream stream) { this.ReadImageHeaders(stream, out _, out _); - - var size = new Size(this.infoHeader.Width, this.infoHeader.Height); - return new BmpInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), size, this.metaData); + return new ImageInfo(new PixelTypeInfo(this.infoHeader.BitsPerPixel), this.infoHeader.Width, this.infoHeader.Height, this.metaData); } /// diff --git a/src/ImageSharp/Formats/Bmp/BmpInfo.cs b/src/ImageSharp/Formats/Bmp/BmpInfo.cs deleted file mode 100644 index dfffe94db7..0000000000 --- a/src/ImageSharp/Formats/Bmp/BmpInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.ImageSharp.MetaData; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Formats.Bmp -{ - /// - /// Contains information about the bmp including dimensions, pixel type information and additional metadata. - /// - public class BmpInfo : ImageInfo - { - /// - /// Initializes a new instance of the class. - /// - /// The image pixel type information. - /// The size of the image in pixels. - /// The images metadata. - internal BmpInfo(PixelTypeInfo pixelType, Size size, ImageMetaData metaData) - : base(pixelType, size, metaData) - { - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifColorTableMode.cs b/src/ImageSharp/Formats/Gif/GifColorTableMode.cs index aa41928633..95b3335626 100644 --- a/src/ImageSharp/Formats/Gif/GifColorTableMode.cs +++ b/src/ImageSharp/Formats/Gif/GifColorTableMode.cs @@ -4,7 +4,7 @@ namespace SixLabors.ImageSharp.Formats.Gif { /// - /// Provides enumeration for the available Gif color table modes. + /// Provides enumeration for the available color table modes. /// public enum GifColorTableMode { diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index 0dbd39b992..cc80b0cce2 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -26,6 +26,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// internal static readonly byte[] MagicNumber = Encoding.UTF8.GetBytes(FileType + FileVersion); + /// + /// Gets the key used for storing and retriving metadata. + /// + public const string MetaDataKey = FileType; + /// /// The extension block introducer !. /// @@ -41,20 +46,25 @@ namespace SixLabors.ImageSharp.Formats.Gif /// public const byte ApplicationExtensionLabel = 0xFF; + /// + /// The application block size. + /// + public const byte ApplicationBlockSize = 11; + /// /// The application identification. /// - public const string ApplicationIdentification = "NETSCAPE2.0"; + public const string NetscapeApplicationIdentification = "NETSCAPE2.0"; /// /// The ASCII encoded application identification bytes. /// - internal static readonly byte[] ApplicationIdentificationBytes = Encoding.UTF8.GetBytes(ApplicationIdentification); + internal static readonly byte[] NetscapeApplicationIdentificationBytes = Encoding.UTF8.GetBytes(NetscapeApplicationIdentification); /// - /// The application block size. + /// The Netscape looping application sub block size. /// - public const byte ApplicationBlockSize = 11; + public const byte NetscapeLoopingSubBlockSize = 3; /// /// The comment label. diff --git a/src/ImageSharp/Formats/Gif/GifDecoder.cs b/src/ImageSharp/Formats/Gif/GifDecoder.cs index ac451a3550..42c76d6400 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoder.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoder.cs @@ -3,6 +3,7 @@ using System.IO; using System.Text; +using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Gif diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index e791517521..092ac859df 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -61,10 +61,15 @@ namespace SixLabors.ImageSharp.Formats.Gif private GifImageDescriptor imageDescriptor; /// - /// The metadata + /// The abstract metadata. /// private ImageMetaData metaData; + /// + /// The gif specific metadata. + /// + private GifMetaData gifMetaData; + /// /// Initializes a new instance of the class. /// @@ -134,11 +139,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadComments(); break; case GifConstants.ApplicationExtensionLabel: - - // The application extension length should be 11 but we've got test images that incorrectly - // set this to 252. - int appLength = stream.ReadByte(); - this.Skip(appLength); // No need to read. + this.ReadApplicationExtension(); break; case GifConstants.PlainTextLabel: int plainLength = stream.ReadByte(); @@ -163,6 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.globalColorTable?.Dispose(); } + image?.MetaData.AddOrUpdateGifMetaData(this.gifMetaData); return image; } @@ -197,11 +199,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.ReadComments(); break; case GifConstants.ApplicationExtensionLabel: - - // The application extension length should be 11 but we've got test images that incorrectly - // set this to 252. - int appLength = stream.ReadByte(); - this.Skip(appLength); // No need to read. + this.ReadApplicationExtension(); break; case GifConstants.PlainTextLabel: int plainLength = stream.ReadByte(); @@ -226,16 +224,11 @@ namespace SixLabors.ImageSharp.Formats.Gif this.globalColorTable?.Dispose(); } - GifColorTableMode colorTableMode = this.logicalScreenDescriptor.GlobalColorTableFlag - ? GifColorTableMode.Global - : GifColorTableMode.Local; - - var size = new Size(this.logicalScreenDescriptor.Width, this.logicalScreenDescriptor.Height); - - return new GifInfo( - colorTableMode, + this.metaData.AddOrUpdateGifMetaData(this.gifMetaData); + return new ImageInfo( new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel), - size, + this.logicalScreenDescriptor.Width, + this.logicalScreenDescriptor.Height, this.metaData); } @@ -269,6 +262,41 @@ namespace SixLabors.ImageSharp.Formats.Gif this.logicalScreenDescriptor = GifLogicalScreenDescriptor.Parse(this.buffer); } + /// + /// Reads the application extension block parsing any animation information + /// if present. + /// + private void ReadApplicationExtension() + { + int appLength = this.stream.ReadByte(); + + // If the length is 11 then it's a valid extension and most likely + // a NETSCAPE or ANIMEXTS extension. We want the loop count from this. + if (appLength == GifConstants.ApplicationBlockSize) + { + this.stream.Skip(appLength); + int subBlockSize = this.stream.ReadByte(); + + // TODO: There's also a NETSCAPE buffer extension. + // http://www.vurdalakov.net/misc/gif/netscape-buffering-application-extension + if (subBlockSize == GifConstants.NetscapeLoopingSubBlockSize) + { + this.stream.Read(this.buffer, 0, GifConstants.NetscapeLoopingSubBlockSize); + this.gifMetaData.RepeatCount = GifNetscapeLoopingApplicationExtension.Parse(this.buffer.AsSpan(1)).RepeatCount; + this.stream.Skip(1); // Skip the terminator. + return; + } + + // Could be XMP or something else not supported yet. + // Back up and skip. + this.stream.Position -= appLength + 1; + this.Skip(appLength); + return; + } + + this.Skip(appLength); // Not supported by any known decoder. + } + /// /// Skips the designated number of bytes in the stream. /// @@ -399,7 +427,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } else { - if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToPrevious) + if (this.graphicsControlExtension.DisposalMethod == GifDisposalMethod.RestoreToPrevious) { prevFrame = previousFrame; } @@ -482,7 +510,7 @@ namespace SixLabors.ImageSharp.Formats.Gif previousFrame = currentFrame ?? image.Frames.RootFrame; - if (this.graphicsControlExtension.DisposalMethod == DisposalMethod.RestoreToBackground) + if (this.graphicsControlExtension.DisposalMethod == GifDisposalMethod.RestoreToBackground) { this.restoreArea = new Rectangle(descriptor.Left, descriptor.Top, descriptor.Width, descriptor.Height); } @@ -514,24 +542,26 @@ namespace SixLabors.ImageSharp.Formats.Gif [MethodImpl(MethodImplOptions.AggressiveInlining)] private void SetFrameMetaData(ImageFrameMetaData meta) { + var gifMeta = new GifFrameMetaData(); if (this.graphicsControlExtension.DelayTime > 0) { - meta.FrameDelay = this.graphicsControlExtension.DelayTime; + gifMeta.FrameDelay = this.graphicsControlExtension.DelayTime; } // Frames can either use the global table or their own local table. if (this.logicalScreenDescriptor.GlobalColorTableFlag && this.logicalScreenDescriptor.GlobalColorTableSize > 0) { - meta.ColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize; + gifMeta.ColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize; } else if (this.imageDescriptor.LocalColorTableFlag && this.imageDescriptor.LocalColorTableSize > 0) { - meta.ColorTableLength = this.imageDescriptor.LocalColorTableSize; + gifMeta.ColorTableLength = this.imageDescriptor.LocalColorTableSize; } - meta.DisposalMethod = this.graphicsControlExtension.DisposalMethod; + gifMeta.DisposalMethod = this.graphicsControlExtension.DisposalMethod; + meta.AddOrUpdateGifFrameMetaData(gifMeta); } /// @@ -575,10 +605,17 @@ namespace SixLabors.ImageSharp.Formats.Gif } this.metaData = meta; + this.gifMetaData = new GifMetaData + { + ColorTableMode = this.logicalScreenDescriptor.GlobalColorTableFlag + ? GifColorTableMode.Global + : GifColorTableMode.Local + }; if (this.logicalScreenDescriptor.GlobalColorTableFlag) { int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3; + this.gifMetaData.GlobalColorTableLength = globalColorTableLength; this.globalColorTable = this.MemoryAllocator.AllocateManagedByteBuffer(globalColorTableLength, AllocationOptions.Clean); diff --git a/src/ImageSharp/Formats/Gif/DisposalMethod.cs b/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs similarity index 97% rename from src/ImageSharp/Formats/Gif/DisposalMethod.cs rename to src/ImageSharp/Formats/Gif/GifDisposalMethod.cs index 5d3e1b4d89..982340db66 100644 --- a/src/ImageSharp/Formats/Gif/DisposalMethod.cs +++ b/src/ImageSharp/Formats/Gif/GifDisposalMethod.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// in an animation sequence. /// section 23 /// - public enum DisposalMethod + public enum GifDisposalMethod { /// /// No disposal specified. diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index e8e28ccdd8..9f376044d3 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Gets or sets the color table mode: Global or local. /// - public GifColorTableMode ColorTableMode { get; set; } + public GifColorTableMode? ColorTableMode { get; set; } /// public void Encode(Image image, Stream stream) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index ab0ee1fb6f..6f0068f351 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers.Binary; using System.IO; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -44,7 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The color table mode: Global or local. /// - private readonly GifColorTableMode colorTableMode; + private GifColorTableMode? colorTableMode; /// /// A flag indicating whether to ingore the metadata when writing the image. @@ -56,6 +55,11 @@ namespace SixLabors.ImageSharp.Formats.Gif /// private int bitDepth; + /// + /// Gif specific meta data. + /// + private GifMetaData gifMetaData; + /// /// Initializes a new instance of the class. /// @@ -66,7 +70,6 @@ namespace SixLabors.ImageSharp.Formats.Gif this.memoryAllocator = memoryAllocator; this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding; this.quantizer = options.Quantizer; - this.colorTableMode = options.ColorTableMode; this.ignoreMetadata = options.IgnoreMetadata; } @@ -82,6 +85,10 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); + this.gifMetaData = image.MetaData.GetGifMetaData() ?? new GifMetaData(); + this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; + bool useGlobalTable = this.colorTableMode.Equals(GifColorTableMode.Global); + // Quantize the image returning a palette. QuantizedFrame quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); @@ -94,7 +101,6 @@ namespace SixLabors.ImageSharp.Formats.Gif // Write the LSD. int index = this.GetTransparentIndex(quantized); - bool useGlobalTable = this.colorTableMode.Equals(GifColorTableMode.Global); this.WriteLogicalScreenDescriptor(image, index, useGlobalTable, stream); if (useGlobalTable) @@ -108,7 +114,7 @@ namespace SixLabors.ImageSharp.Formats.Gif // Write application extension to allow additional frames. if (image.Frames.Count > 1) { - this.WriteApplicationExtension(stream, image.MetaData.RepeatCount); + this.WriteApplicationExtension(stream, this.gifMetaData.RepeatCount); } if (useGlobalTable) @@ -136,8 +142,8 @@ namespace SixLabors.ImageSharp.Formats.Gif for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; - - this.WriteGraphicalControlExtension(frame.MetaData, transparencyIndex, stream); + GifFrameMetaData frameMetaData = frame.MetaData.GetGifFrameMetaData() ?? new GifFrameMetaData(); + this.WriteGraphicalControlExtension(frameMetaData, transparencyIndex, stream); this.WriteImageDescriptor(frame, false, stream); if (i == 0) @@ -159,16 +165,18 @@ namespace SixLabors.ImageSharp.Formats.Gif where TPixel : struct, IPixel { ImageFrame previousFrame = null; + GifFrameMetaData previousMeta = null; foreach (ImageFrame frame in image.Frames) { + GifFrameMetaData meta = frame.MetaData.GetGifFrameMetaData() ?? new GifFrameMetaData(); if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. if (previousFrame != null - && previousFrame.MetaData.ColorTableLength != frame.MetaData.ColorTableLength - && frame.MetaData.ColorTableLength > 0) + && previousMeta.ColorTableLength != meta.ColorTableLength + && meta.ColorTableLength > 0) { - quantized = this.quantizer.CreateFrameQuantizer(frame.MetaData.ColorTableLength).QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer(meta.ColorTableLength).QuantizeFrame(frame); } else { @@ -177,7 +185,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); - this.WriteGraphicalControlExtension(frame.MetaData, this.GetTransparentIndex(quantized), stream); + this.WriteGraphicalControlExtension(meta, this.GetTransparentIndex(quantized), stream); this.WriteImageDescriptor(frame, true, stream); this.WriteColorTable(quantized, stream); this.WriteImageData(quantized, stream); @@ -185,6 +193,7 @@ namespace SixLabors.ImageSharp.Formats.Gif quantized?.Dispose(); quantized = null; // So next frame can regenerate it previousFrame = frame; + previousMeta = meta; } } @@ -290,25 +299,8 @@ namespace SixLabors.ImageSharp.Formats.Gif // Application Extension Header if (repeatCount != 1) { - this.buffer[0] = GifConstants.ExtensionIntroducer; - this.buffer[1] = GifConstants.ApplicationExtensionLabel; - this.buffer[2] = GifConstants.ApplicationBlockSize; - - // Write NETSCAPE2.0 - GifConstants.ApplicationIdentificationBytes.AsSpan().CopyTo(this.buffer.AsSpan(3, 11)); - - // Application Data ---- - this.buffer[14] = 3; // Application block length - this.buffer[15] = 1; // Data sub-block index (always 1) - - // 0 means loop indefinitely. Count is set as play n + 1 times. - repeatCount = (ushort)Math.Max(0, repeatCount - 1); - - BinaryPrimitives.WriteUInt16LittleEndian(this.buffer.AsSpan(16, 2), repeatCount); // Repeat count for images. - - this.buffer[18] = GifConstants.Terminator; // Terminator - - stream.Write(this.buffer, 0, 19); + var loopingExtension = new GifNetscapeLoopingApplicationExtension(repeatCount); + this.WriteExtension(loopingExtension, stream); } } @@ -348,7 +340,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The metadata of the image or frame. /// The index of the color in the color palette to make transparent. /// The stream to write to. - private void WriteGraphicalControlExtension(ImageFrameMetaData metaData, int transparencyIndex, Stream stream) + private void WriteGraphicalControlExtension(GifFrameMetaData metaData, int transparencyIndex, Stream stream) { byte packedValue = GifGraphicControlExtension.GetPackedValue( disposalMethod: metaData.DisposalMethod, diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs new file mode 100644 index 0000000000..cc04d48314 --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -0,0 +1,33 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Gif +{ + /// + /// Provides Gif specific metadata information for the image frame. + /// + public class GifFrameMetaData + { + /// + /// Gets or sets the length of the color table for paletted images. + /// If not 0, then this field indicates the maximum number of colors to use when quantizing the + /// image frame. + /// + public int ColorTableLength { get; set; } + + /// + /// Gets or sets the frame delay for animated images. + /// If not 0, when utilized in Gif animation, this field specifies the number of hundredths (1/100) of a second to + /// wait before continuing with the processing of the Data Stream. + /// The clock starts ticking immediately after the graphic is rendered. + /// + public int FrameDelay { get; set; } + + /// + /// Gets or sets the disposal method for animated images. + /// Primarily used in Gif animation, this field indicates the way in which the graphic is to + /// be treated after being displayed. + /// + public GifDisposalMethod DisposalMethod { get; set; } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifInfo.cs b/src/ImageSharp/Formats/Gif/GifInfo.cs deleted file mode 100644 index 1c345a576b..0000000000 --- a/src/ImageSharp/Formats/Gif/GifInfo.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.ImageSharp.MetaData; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Formats.Gif -{ - /// - /// Contains information about the bmp including dimensions, pixel type information and additional metadata. - /// - public class GifInfo : ImageInfo - { - /// - /// Initializes a new instance of the class. - /// - /// The color table mode. - /// The image pixel type information. - /// The size of the image in pixels. - /// The images metadata. - internal GifInfo( - GifColorTableMode colorTableMode, - PixelTypeInfo pixelType, - Size size, - ImageMetaData metaData) - : base(pixelType, size, metaData) => this.ColorTableMode = colorTableMode; - - /// - /// Gets the color table mode. - /// - public GifColorTableMode ColorTableMode { get; } - } -} diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs new file mode 100644 index 0000000000..f58f5dff3e --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -0,0 +1,29 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Gif +{ + /// + /// Provides Gif specific metadata information for the image. + /// + public class GifMetaData + { + /// + /// Gets or sets the number of times any animation is repeated. + /// + /// 0 means to repeat indefinitely, count is set as play n + 1 times + /// + /// + public ushort RepeatCount { get; set; } + + /// + /// Gets or sets the color table mode. + /// + public GifColorTableMode ColorTableMode { get; set; } + + /// + /// Gets or sets the length of the global color table if present. + /// + public int GlobalColorTableLength { get; set; } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs b/src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs new file mode 100644 index 0000000000..04b542d2d6 --- /dev/null +++ b/src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs @@ -0,0 +1,49 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData; + +namespace SixLabors.ImageSharp.Formats.Gif +{ + /// + /// Extension methods for storing meta data specific to Gif images. + /// + public static class GifMetaDataExtensions + { + /// + /// Adds or updates the Gif specific meta data to the image. + /// + /// The image meta data. + /// The gif meta data. + public static void AddOrUpdateGifMetaData(this ImageMetaData meta, GifMetaData value) => meta.AddOrUpdateMetaData(GifConstants.MetaDataKey, value); + + /// + /// Gets the Gif format specific meta data from the image. + /// + /// The image meta data. + /// The or null. + public static GifMetaData GetGifMetaData(this ImageMetaData meta) + { + meta.TryGetMetaData(GifConstants.MetaDataKey, out GifMetaData value); + return value; + } + + /// + /// Adds or updates the Gif specific meta data to the image frame. + /// + /// The image meta data. + /// The gif meta data. + public static void AddOrUpdateGifFrameMetaData(this ImageFrameMetaData meta, GifFrameMetaData value) => meta.AddOrUpdateMetaData(GifConstants.MetaDataKey, value); + + /// + /// Gets the Gif format specific meta data from the image frame. + /// + /// The image meta data. + /// The or null. + public static GifFrameMetaData GetGifFrameMetaData(this ImageFrameMetaData meta) + { + meta.TryGetMetaData(GifConstants.MetaDataKey, out GifFrameMetaData value); + return value; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs index e99f09add3..42c202a3d9 100644 --- a/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs +++ b/src/ImageSharp/Formats/Gif/IGifDecoderOptions.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Text; +using SixLabors.ImageSharp.MetaData; namespace SixLabors.ImageSharp.Formats.Gif { diff --git a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs index bad6e0031b..7dd558c803 100644 --- a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs +++ b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs @@ -29,6 +29,6 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Gets the color table mode: Global or local. /// - GifColorTableMode ColorTableMode { get; } + GifColorTableMode? ColorTableMode { get; } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs index 7ec5f20309..cb548d687d 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs +++ b/src/ImageSharp/Formats/Gif/Sections/GifGraphicControlExtension.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Gets the disposal method which indicates the way in which the /// graphic is to be treated after being displayed. /// - public DisposalMethod DisposalMethod => (DisposalMethod)((this.Packed & 0x1C) >> 2); + public GifDisposalMethod DisposalMethod => (GifDisposalMethod)((this.Packed & 0x1C) >> 2); /// /// Gets a value indicating whether transparency flag is to be set. @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Formats.Gif return MemoryMarshal.Cast(buffer)[0]; } - public static byte GetPackedValue(DisposalMethod disposalMethod, bool userInputFlag = false, bool transparencyFlag = false) + public static byte GetPackedValue(GifDisposalMethod disposalMethod, bool userInputFlag = false, bool transparencyFlag = false) { /* Reserved | 3 Bits diff --git a/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs b/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs new file mode 100644 index 0000000000..49a52edf6a --- /dev/null +++ b/src/ImageSharp/Formats/Gif/Sections/GifNetscapeLoopingApplicationExtension.cs @@ -0,0 +1,44 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers.Binary; + +namespace SixLabors.ImageSharp.Formats.Gif +{ + internal readonly struct GifNetscapeLoopingApplicationExtension : IGifExtension + { + public GifNetscapeLoopingApplicationExtension(ushort repeatCount) => this.RepeatCount = repeatCount; + + public byte Label => GifConstants.ApplicationExtensionLabel; + + /// + /// Gets the repeat count. + /// 0 means loop indefinitely. Count is set as play n + 1 times. + /// + public ushort RepeatCount { get; } + + public static GifNetscapeLoopingApplicationExtension Parse(ReadOnlySpan buffer) + { + ushort repeatCount = BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(0, 2)); + return new GifNetscapeLoopingApplicationExtension(repeatCount); + } + + public int WriteTo(Span buffer) + { + buffer[0] = GifConstants.ApplicationBlockSize; + + // Write NETSCAPE2.0 + GifConstants.NetscapeApplicationIdentificationBytes.AsSpan().CopyTo(buffer.Slice(1, 11)); + + // Application Data ---- + buffer[12] = 3; // Application block length (always 3) + buffer[13] = 1; // Data sub-block indentity (always 1) + + // 0 means loop indefinitely. Count is set as play n + 1 times. + BinaryPrimitives.WriteUInt16LittleEndian(buffer.Slice(14, 2), this.RepeatCount); + + return 16; // Length - Introducer + Label + Terminator. + } + } +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index fb717d3fb8..8c5230a1c4 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -235,7 +235,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.InitIccProfile(); this.InitDerivedMetaDataProperties(); - return new JpegInfo(new PixelTypeInfo(this.BitsPerPixel), new Size(this.ImageWidth, this.ImageHeight), this.MetaData); + return new ImageInfo(new PixelTypeInfo(this.BitsPerPixel), this.ImageWidth, this.ImageHeight, this.MetaData); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegInfo.cs b/src/ImageSharp/Formats/Jpeg/JpegInfo.cs deleted file mode 100644 index 8e9b6257c3..0000000000 --- a/src/ImageSharp/Formats/Jpeg/JpegInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.ImageSharp.MetaData; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Formats.Jpeg -{ - /// - /// Contains information about the bmp including dimensions, pixel type information and additional metadata. - /// - public class JpegInfo : ImageInfo - { - /// - /// Initializes a new instance of the class. - /// - /// The image pixel type information. - /// The size of the image in pixels. - /// The images metadata. - internal JpegInfo(PixelTypeInfo pixelType, Size size, ImageMetaData metaData) - : base(pixelType, size, metaData) - { - } - } -} diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 9032560160..be1914174b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -17,7 +17,6 @@ using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; -using SixLabors.Primitives; namespace SixLabors.ImageSharp.Formats.Png { @@ -349,7 +348,7 @@ namespace SixLabors.ImageSharp.Formats.Png throw new ImageFormatException("PNG Image does not contain a header chunk"); } - return new PngInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), new Size(this.header.Width, this.header.Height), metadata); + return new ImageInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), this.header.Width, this.header.Height, metadata); } /// diff --git a/src/ImageSharp/Formats/Png/PngInfo.cs b/src/ImageSharp/Formats/Png/PngInfo.cs deleted file mode 100644 index 2bb0b16b70..0000000000 --- a/src/ImageSharp/Formats/Png/PngInfo.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.ImageSharp.MetaData; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Formats.Png -{ - /// - /// Contains information about the bmp including dimensions, pixel type information and additional metadata. - /// - public class PngInfo : ImageInfo - { - /// - /// Initializes a new instance of the class. - /// - /// The image pixel type information. - /// The size of the image in pixels. - /// The images metadata. - internal PngInfo(PixelTypeInfo pixelType, Size size, ImageMetaData metaData) - : base(pixelType, size, metaData) - { - } - } -} diff --git a/src/ImageSharp/ImageInfo.cs b/src/ImageSharp/ImageInfo.cs index eed1c66918..6f894cb599 100644 --- a/src/ImageSharp/ImageInfo.cs +++ b/src/ImageSharp/ImageInfo.cs @@ -3,26 +3,26 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData; -using SixLabors.Primitives; namespace SixLabors.ImageSharp { /// /// Contains information about the image including dimensions, pixel type information and additional metadata /// - public abstract class ImageInfo : IImageInfo + internal sealed class ImageInfo : IImageInfo { /// /// Initializes a new instance of the class. /// /// The image pixel type information. - /// The size of the image in pixels. + /// The width of the image in pixels. + /// The height of the image in pixels. /// The images metadata. - protected ImageInfo(PixelTypeInfo pixelType, Size size, ImageMetaData metaData) + public ImageInfo(PixelTypeInfo pixelType, int width, int height, ImageMetaData metaData) { this.PixelType = pixelType; - this.Width = size.Width; - this.Height = size.Height; + this.Width = width; + this.Height = height; this.MetaData = metaData; } diff --git a/src/ImageSharp/Formats/Gif/FrameDecodingMode.cs b/src/ImageSharp/MetaData/FrameDecodingMode.cs similarity index 91% rename from src/ImageSharp/Formats/Gif/FrameDecodingMode.cs rename to src/ImageSharp/MetaData/FrameDecodingMode.cs index 05791c92e5..2863fbf8f9 100644 --- a/src/ImageSharp/Formats/Gif/FrameDecodingMode.cs +++ b/src/ImageSharp/MetaData/FrameDecodingMode.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -namespace SixLabors.ImageSharp.Formats.Gif +namespace SixLabors.ImageSharp.MetaData { /// /// Enumerated frame process modes to apply to multi-frame images. diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index f83e092c9f..55678789e5 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -1,7 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.Formats.Gif; +using System; +using System.Collections.Generic; namespace SixLabors.ImageSharp.MetaData { @@ -10,6 +11,8 @@ namespace SixLabors.ImageSharp.MetaData /// public sealed class ImageFrameMetaData { + private readonly Dictionary metaData = new Dictionary(StringComparer.OrdinalIgnoreCase); + /// /// Initializes a new instance of the class. /// @@ -28,37 +31,57 @@ namespace SixLabors.ImageSharp.MetaData { DebugGuard.NotNull(other, nameof(other)); - this.ColorTableLength = other.ColorTableLength; - this.FrameDelay = other.FrameDelay; - this.DisposalMethod = other.DisposalMethod; + foreach (KeyValuePair meta in other.metaData) + { + this.metaData.Add(meta.Key, meta.Value); + } } /// - /// Gets or sets the length of the color table for paletted images. - /// If not 0, then this field indicates the maximum number of colors to use when quantizing the - /// image frame. + /// Clones this ImageFrameMetaData. /// - public int ColorTableLength { get; set; } + /// The cloned instance. + public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); /// - /// Gets or sets the frame delay for animated images. - /// If not 0, when utilized in Gif animation, this field specifies the number of hundredths (1/100) of a second to - /// wait before continuing with the processing of the Data Stream. - /// The clock starts ticking immediately after the graphic is rendered. + /// Adds or updates the specified key and value to the . /// - public int FrameDelay { get; set; } + /// The key of the metadata to add. + /// The value of the element to add. + /// key is null. + /// value is null. + /// An element with the same key already exists in the . + public void AddOrUpdateMetaData(string key, object value) + { + // Don't think this needs to be threadsafe. + Guard.NotNull(value, nameof(value)); + this.metaData[key] = value; + } /// - /// Gets or sets the disposal method for animated images. - /// Primarily used in Gif animation, this field indicates the way in which the graphic is to - /// be treated after being displayed. + /// Gets the metadata value associated with the specified key. /// - public DisposalMethod DisposalMethod { get; set; } + /// The type of value. + /// The key of the value to get. + /// + /// When this method returns, contains the metadata value associated with the specified key, + /// if the key is found; otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// + /// true if the contains an element with + /// the specified key; otherwise, false. + /// + public bool TryGetMetaData(string key, out T value) + { + if (this.metaData.TryGetValue(key, out object meta)) + { + value = (T)meta; + return true; + } - /// - /// Clones this ImageFrameMetaData. - /// - /// The cloned instance. - public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); + value = default; + return false; + } } } \ No newline at end of file diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 40880bd085..8233798c22 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Collections.Generic; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Icc; @@ -24,6 +25,7 @@ namespace SixLabors.ImageSharp.MetaData /// public const double DefaultVerticalResolution = 96; + private readonly Dictionary metaData = new Dictionary(StringComparer.OrdinalIgnoreCase); private double horizontalResolution; private double verticalResolution; @@ -48,7 +50,11 @@ namespace SixLabors.ImageSharp.MetaData this.HorizontalResolution = other.HorizontalResolution; this.VerticalResolution = other.VerticalResolution; this.ResolutionUnits = other.ResolutionUnits; - this.RepeatCount = other.RepeatCount; + + foreach (KeyValuePair meta in other.metaData) + { + this.metaData.Add(meta.Key, meta.Value); + } foreach (ImageProperty property in other.Properties) { @@ -125,10 +131,51 @@ namespace SixLabors.ImageSharp.MetaData public IList Properties { get; } = new List(); /// - /// Gets or sets the number of times any animation is repeated. - /// 0 means to repeat indefinitely. + /// Adds or updates the specified key and value to the . + /// + /// The key of the metadata to add. + /// The value of the element to add. + /// key is null. + /// value is null. + /// An element with the same key already exists in the . + public void AddOrUpdateMetaData(string key, object value) + { + // Don't think this needs to be threadsafe. + Guard.NotNull(value, nameof(value)); + this.metaData[key] = value; + } + + /// + /// Gets the metadata value associated with the specified key. /// - public ushort RepeatCount { get; set; } + /// The type of value. + /// The key of the value to get. + /// + /// When this method returns, contains the metadata value associated with the specified key, + /// if the key is found; otherwise, the default value for the type of the value parameter. + /// This parameter is passed uninitialized. + /// + /// + /// true if the contains an element with + /// the specified key; otherwise, false. + /// + public bool TryGetMetaData(string key, out T value) + { + if (this.metaData.TryGetValue(key, out object meta)) + { + value = (T)meta; + return true; + } + + value = default; + return false; + } + + /// + /// Clones this into a new instance + /// + /// The cloned metadata instance + public ImageMetaData Clone() => new ImageMetaData(this); /// /// Looks up a property with the provided name. @@ -153,21 +200,9 @@ namespace SixLabors.ImageSharp.MetaData return false; } - /// - /// Clones this into a new instance - /// - /// The cloned metadata instance - public ImageMetaData Clone() - { - return new ImageMetaData(this); - } - /// /// Synchronizes the profiles with the current meta data. /// - internal void SyncProfiles() - { - this.ExifProfile?.Sync(this); - } + internal void SyncProfiles() => this.ExifProfile?.Sync(this); } } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 11fa4d5d5f..2b08bf20de 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -186,32 +186,37 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif using (var inStream = new MemoryStream(TestFile.Create(TestImages.Gif.Leo).Bytes)) using (var outStream = new MemoryStream()) { - var info = (GifInfo)Image.Identify(inStream); - GifColorTableMode colorMode = info.ColorTableMode; inStream.Position = 0; var image = Image.Load(inStream); + GifMetaData metaData = image.MetaData.GetGifMetaData(); + GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetGifFrameMetaData(); + GifColorTableMode colorMode = metaData.ColorTableMode; var encoder = new GifEncoder() { ColorTableMode = colorMode, - Quantizer = new OctreeQuantizer(image.Frames.RootFrame.MetaData.ColorTableLength) + Quantizer = new OctreeQuantizer(frameMetaData.ColorTableLength) }; image.Save(outStream, encoder); outStream.Position = 0; - var cloneInfo = (GifInfo)Image.Identify(outStream); outStream.Position = 0; var clone = Image.Load(outStream); + GifMetaData cloneMetaData = clone.MetaData.GetGifMetaData(); + Assert.Equal(metaData.ColorTableMode, cloneMetaData.ColorTableMode); + // Gifiddle and Cyotek GifInfo say this image has 64 colors. - Assert.Equal(64, image.Frames.RootFrame.MetaData.ColorTableLength); - Assert.Equal(info.ColorTableMode, cloneInfo.ColorTableMode); + Assert.Equal(64, frameMetaData.ColorTableLength); for (int i = 0; i < image.Frames.Count; i++) { - Assert.Equal(image.Frames[i].MetaData.ColorTableLength, clone.Frames[i].MetaData.ColorTableLength); - Assert.Equal(image.Frames[i].MetaData.FrameDelay, clone.Frames[i].MetaData.FrameDelay); + GifFrameMetaData ifm = image.Frames[i].MetaData.GetGifFrameMetaData(); + GifFrameMetaData cifm = clone.Frames[i].MetaData.GetGifFrameMetaData(); + + Assert.Equal(ifm.ColorTableLength, cifm.ColorTableLength); + Assert.Equal(ifm.FrameDelay, cifm.FrameDelay); } image.Dispose(); diff --git a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs index 2790b1a576..dc0da5e2db 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifGraphicControlExtensionTests.cs @@ -12,10 +12,10 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif [Fact] public void TestPackedValue() { - Assert.Equal(0, GifGraphicControlExtension.GetPackedValue(DisposalMethod.Unspecified, false, false)); - Assert.Equal(11, GifGraphicControlExtension.GetPackedValue(DisposalMethod.RestoreToBackground, true, true)); - Assert.Equal(4, GifGraphicControlExtension.GetPackedValue(DisposalMethod.NotDispose, false, false)); - Assert.Equal(14, GifGraphicControlExtension.GetPackedValue(DisposalMethod.RestoreToPrevious, true, false)); + Assert.Equal(0, GifGraphicControlExtension.GetPackedValue(GifDisposalMethod.Unspecified, false, false)); + Assert.Equal(11, GifGraphicControlExtension.GetPackedValue(GifDisposalMethod.RestoreToBackground, true, true)); + Assert.Equal(4, GifGraphicControlExtension.GetPackedValue(GifDisposalMethod.NotDispose, false, false)); + Assert.Equal(14, GifGraphicControlExtension.GetPackedValue(GifDisposalMethod.RestoreToPrevious, true, false)); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/ImageInfoTests.cs b/tests/ImageSharp.Tests/ImageInfoTests.cs index d46e340521..91f6804c0f 100644 --- a/tests/ImageSharp.Tests/ImageInfoTests.cs +++ b/tests/ImageSharp.Tests/ImageInfoTests.cs @@ -2,10 +2,6 @@ // Licensed under the Apache License, Version 2.0. using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Bmp; -using SixLabors.ImageSharp.Formats.Gif; -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.MetaData; using SixLabors.Primitives; @@ -16,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests public class ImageInfoTests { [Fact] - public void JpegInfoInitializesCorrectly() + public void ImageInfoInitializesCorrectly() { const int Width = 50; const int Height = 60; @@ -25,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests var pixelType = new PixelTypeInfo(8); var meta = new ImageMetaData(); - var info = new JpegInfo(pixelType, size, meta); + var info = new ImageInfo(pixelType, Width, Height, meta); Assert.Equal(pixelType, info.PixelType); Assert.Equal(Width, info.Width); @@ -34,67 +30,5 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(rectangle, info.Bounds()); Assert.Equal(meta, info.MetaData); } - - [Fact] - public void BmpInfoInitializesCorrectly() - { - const int Width = 50; - const int Height = 60; - var size = new Size(Width, Height); - var rectangle = new Rectangle(0, 0, Width, Height); - var pixelType = new PixelTypeInfo(8); - var meta = new ImageMetaData(); - - var info = new BmpInfo(pixelType, size, meta); - - Assert.Equal(pixelType, info.PixelType); - Assert.Equal(Width, info.Width); - Assert.Equal(Height, info.Height); - Assert.Equal(size, info.Size()); - Assert.Equal(rectangle, info.Bounds()); - Assert.Equal(meta, info.MetaData); - } - - [Fact] - public void PngInfoInitializesCorrectly() - { - const int Width = 50; - const int Height = 60; - var size = new Size(Width, Height); - var rectangle = new Rectangle(0, 0, Width, Height); - var pixelType = new PixelTypeInfo(8); - var meta = new ImageMetaData(); - - var info = new PngInfo(pixelType, size, meta); - - Assert.Equal(pixelType, info.PixelType); - Assert.Equal(Width, info.Width); - Assert.Equal(Height, info.Height); - Assert.Equal(size, info.Size()); - Assert.Equal(rectangle, info.Bounds()); - Assert.Equal(meta, info.MetaData); - } - - [Fact] - public void GifInfoInitializesCorrectly() - { - const GifColorTableMode mode = GifColorTableMode.Local; - const int Width = 50; - const int Height = 60; - var size = new Size(Width, Height); - var rectangle = new Rectangle(0, 0, Width, Height); - var pixelType = new PixelTypeInfo(8); - var meta = new ImageMetaData(); - - var info = new GifInfo(mode, pixelType, size, meta); - - Assert.Equal(mode, info.ColorTableMode); - Assert.Equal(pixelType, info.PixelType); - Assert.Equal(Width, info.Width); - Assert.Equal(Height, info.Height); - Assert.Equal(size, info.Size()); - Assert.Equal(rectangle, info.Bounds()); - Assert.Equal(meta, info.MetaData); - } } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 6e18fe2537..c250d973b5 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -17,20 +17,24 @@ namespace SixLabors.ImageSharp.Tests { const int frameDelay = 42; const int colorTableLength = 128; - const DisposalMethod disposalMethod = DisposalMethod.RestoreToBackground; + const GifDisposalMethod disposalMethod = GifDisposalMethod.RestoreToBackground; - var metaData = new ImageFrameMetaData + var gifFrameMetaData = new GifFrameMetaData { FrameDelay = frameDelay, ColorTableLength = colorTableLength, DisposalMethod = disposalMethod }; + var metaData = new ImageFrameMetaData(); + metaData.AddOrUpdateGifFrameMetaData(gifFrameMetaData); + var clone = new ImageFrameMetaData(metaData); + GifFrameMetaData cloneGifFrameMetaData = clone.GetGifFrameMetaData(); - Assert.Equal(frameDelay, clone.FrameDelay); - Assert.Equal(colorTableLength, clone.ColorTableLength); - Assert.Equal(disposalMethod, clone.DisposalMethod); + Assert.Equal(frameDelay, cloneGifFrameMetaData.FrameDelay); + Assert.Equal(colorTableLength, cloneGifFrameMetaData.ColorTableLength); + Assert.Equal(disposalMethod, cloneGifFrameMetaData.DisposalMethod); } } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index 8934ebc361..d681c90ba2 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -28,7 +28,6 @@ namespace SixLabors.ImageSharp.Tests metaData.HorizontalResolution = 4; metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - metaData.RepeatCount = 1; ImageMetaData clone = metaData.Clone(); @@ -36,7 +35,6 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(4, clone.HorizontalResolution); Assert.Equal(2, clone.VerticalResolution); Assert.Equal(imageProperty, clone.Properties[0]); - Assert.Equal(1, clone.RepeatCount); } [Fact] diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs index 3696accdd3..427a565424 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/SystemDrawingReferenceDecoder.cs @@ -48,16 +48,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs using (var sourceBitmap = new System.Drawing.Bitmap(stream)) { var pixelType = new PixelTypeInfo(System.Drawing.Image.GetPixelFormatSize(sourceBitmap.PixelFormat)); - var size = new SixLabors.Primitives.Size(sourceBitmap.Width, sourceBitmap.Height); - return new SystemDrawingInfo(pixelType, size, new ImageMetaData()); - } - } - - private class SystemDrawingInfo : ImageInfo - { - public SystemDrawingInfo(PixelTypeInfo pixelType, SixLabors.Primitives.Size size, ImageMetaData metaData) - : base(pixelType, size, metaData) - { + return new ImageInfo(pixelType, sourceBitmap.Width, sourceBitmap.Height, new ImageMetaData()); } } } From 72d1d277b278d2c30a1b96832745812807afdac6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 6 Sep 2018 10:44:10 +0100 Subject: [PATCH 042/185] Fix local color table encoding. --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 3 ++- .../Formats/Gif/Sections/GifImageDescriptor.cs | 2 +- .../Gif/Sections/GifImageDescriptorTests.cs | 14 +++++++------- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 6f0068f351..b373446589 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -71,6 +71,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding; this.quantizer = options.Quantizer; this.ignoreMetadata = options.IgnoreMetadata; + this.colorTableMode = options.ColorTableMode; } /// @@ -246,7 +247,7 @@ namespace SixLabors.ImageSharp.Formats.Gif private void WriteLogicalScreenDescriptor(Image image, int transparencyIndex, bool useGlobalTable, Stream stream) where TPixel : struct, IPixel { - byte packedValue = GifLogicalScreenDescriptor.GetPackedValue(useGlobalTable, this.bitDepth, false, this.bitDepth - 1); + byte packedValue = GifLogicalScreenDescriptor.GetPackedValue(useGlobalTable, this.bitDepth - 1, false, this.bitDepth - 1); // The Pixel Aspect Ratio is defined to be the quotient of the pixel's // width over its height. The value range in this field allows diff --git a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs index e2f5bee78e..c3504dfe7b 100644 --- a/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs +++ b/src/ImageSharp/Formats/Gif/Sections/GifImageDescriptor.cs @@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Gif value |= 1 << 5; } - value |= (byte)(localColorTableSize - 1); + value |= (byte)localColorTableSize; return value; } diff --git a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifImageDescriptorTests.cs b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifImageDescriptorTests.cs index 4ef4c12d97..6a90c0c277 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/Sections/GifImageDescriptorTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/Sections/GifImageDescriptorTests.cs @@ -12,13 +12,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif [Fact] public void TestPackedValue() { - Assert.Equal(128, GifImageDescriptor.GetPackedValue(true, false, false, 1)); // localColorTable - Assert.Equal(64, GifImageDescriptor.GetPackedValue(false, true, false, 1)); // interfaceFlag - Assert.Equal(32, GifImageDescriptor.GetPackedValue(false, false, true, 1)); // sortFlag - Assert.Equal(224, GifImageDescriptor.GetPackedValue(true, true, true, 1)); // all - Assert.Equal(7, GifImageDescriptor.GetPackedValue(false, false, false, 8)); - Assert.Equal(227, GifImageDescriptor.GetPackedValue(true, true, true, 4)); - Assert.Equal(231, GifImageDescriptor.GetPackedValue(true, true, true, 8)); + Assert.Equal(129, GifImageDescriptor.GetPackedValue(true, false, false, 1)); // localColorTable + Assert.Equal(65, GifImageDescriptor.GetPackedValue(false, true, false, 1)); // interfaceFlag + Assert.Equal(33, GifImageDescriptor.GetPackedValue(false, false, true, 1)); // sortFlag + Assert.Equal(225, GifImageDescriptor.GetPackedValue(true, true, true, 1)); // all + Assert.Equal(8, GifImageDescriptor.GetPackedValue(false, false, false, 8)); + Assert.Equal(228, GifImageDescriptor.GetPackedValue(true, true, true, 4)); + Assert.Equal(232, GifImageDescriptor.GetPackedValue(true, true, true, 8)); } } } \ No newline at end of file From 681df46c2d1afa9c58c32e374263bee1ebbad6be Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Thu, 6 Sep 2018 22:01:49 +0200 Subject: [PATCH 043/185] trying to improve Opacity out of range propagation. For some reason, FillRegionProcessor and DrawTextProcessor where overshooting opacity over 1 --- .../Processors/Drawing/FillRegionProcessor.cs | 20 ++++++++++++------- .../Processors/Text/DrawTextProcessor.cs | 12 ++++++++--- .../Processing/SolidBrush{TPixel}.cs | 15 +++++++++++--- 3 files changed, 34 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 514249a2d4..6ca4f147a5 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -139,9 +139,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { for (float x = scanStart; x < startX + 1; x += subpixelFraction) { - scanline[startX] += subpixelFractionPoint; - scanlineDirty = true; - } + scanline[startX] += subpixelFractionPoint; + scanlineDirty = true; + } + + if (scanline[startX] > 1) { scanline[startX] = 1; } } if (endX >= 0 && endX < scanline.Length) @@ -149,8 +151,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing for (float x = endX; x < scanEnd; x += subpixelFraction) { scanline[endX] += subpixelFractionPoint; - scanlineDirty = true; - } + scanlineDirty = true; + } + + if (scanline[endX] > 1) { scanline[endX] = 1; } } int nextX = startX + 1; @@ -158,8 +162,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing nextX = Math.Max(nextX, 0); for (int x = nextX; x < endX; x++) { - scanline[x] += subpixelFraction; - scanlineDirty = true; + scanline[x] += subpixelFraction; + scanlineDirty = true; + + if (scanline[x] > 1) { scanline[x] = 1; } } } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index 1095de325f..5f42dc3e58 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -386,7 +386,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text { scanline[startX] += subpixelFractionPoint; scanlineDirty = true; - } + } + + if (scanline[startX] > 1) { scanline[startX] = 1; } } if (endX >= 0 && endX < scanline.Length) @@ -395,7 +397,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text { scanline[endX] += subpixelFractionPoint; scanlineDirty = true; - } + } + + if (scanline[endX] > 1) { scanline[endX] = 1; } } int nextX = startX + 1; @@ -404,7 +408,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text for (int x = nextX; x < endX; x++) { scanline[x] += subpixelFraction; - scanlineDirty = true; + scanlineDirty = true; + + if (scanline[x] > 1) { scanline[x] = 1; } } } } diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs index 6b69c33f07..7e724572a9 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs @@ -91,9 +91,18 @@ namespace SixLabors.ImageSharp.Processing { Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; + MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; + +#if DEBUG + for (int i = 0; i < scanline.Length; i++) + { + Guard.MustBeBetweenOrEqualTo(scanline[i], 0, 1, nameof(scanline)); + } +#endif + + float opacity = this.Options.BlendPercentage.Clamp(0, 1); - if (this.Options.BlendPercentage == 1f) + if (opacity == 1f) { this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); } @@ -105,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing for (int i = 0; i < scanline.Length; i++) { - amountSpan[i] = scanline[i] * this.Options.BlendPercentage; + amountSpan[i] = scanline[i] * opacity; } this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan); From e0a056782fc5450629d7a883afaac48c9cdff284 Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Thu, 6 Sep 2018 22:17:42 +0200 Subject: [PATCH 044/185] expanding blocks... --- .../Processors/Drawing/FillRegionProcessor.cs | 15 ++++++++++++--- .../Processors/Text/DrawTextProcessor.cs | 15 ++++++++++++--- 2 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index 6ca4f147a5..d44251d073 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -143,7 +143,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing scanlineDirty = true; } - if (scanline[startX] > 1) { scanline[startX] = 1; } + if (scanline[startX] > 1) + { + scanline[startX] = 1; + } } if (endX >= 0 && endX < scanline.Length) @@ -154,7 +157,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing scanlineDirty = true; } - if (scanline[endX] > 1) { scanline[endX] = 1; } + if (scanline[endX] > 1) + { + scanline[endX] = 1; + } } int nextX = startX + 1; @@ -165,7 +171,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing scanline[x] += subpixelFraction; scanlineDirty = true; - if (scanline[x] > 1) { scanline[x] = 1; } + if (scanline[x] > 1) + { + scanline[x] = 1; + } } } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index 5f42dc3e58..d7a46c1be9 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -388,7 +388,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text scanlineDirty = true; } - if (scanline[startX] > 1) { scanline[startX] = 1; } + if (scanline[startX] > 1) + { + scanline[startX] = 1; + } } if (endX >= 0 && endX < scanline.Length) @@ -399,7 +402,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text scanlineDirty = true; } - if (scanline[endX] > 1) { scanline[endX] = 1; } + if (scanline[endX] > 1) + { + scanline[endX] = 1; + } } int nextX = startX + 1; @@ -410,7 +416,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text scanline[x] += subpixelFraction; scanlineDirty = true; - if (scanline[x] > 1) { scanline[x] = 1; } + if (scanline[x] > 1) + { + scanline[x] = 1; + } } } } From cf2e641000c832f3bdb0ff55b6e19ba6798a8f4a Mon Sep 17 00:00:00 2001 From: Dirk Lemstra Date: Thu, 6 Sep 2018 22:27:28 +0200 Subject: [PATCH 045/185] Allow several invalid data types when reading the exif resolution. --- .../Formats/Jpeg/JpegDecoderCore.cs | 29 ++++++++++++++----- 1 file changed, 22 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 7561afa1ef..cd960a241f 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -463,13 +463,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } else if (this.isExif) { - double horizontalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.XResolution, out ExifValue horizontalTag) - ? ((Rational)horizontalTag.Value).ToDouble() - : 0; - - double verticalValue = this.MetaData.ExifProfile.TryGetValue(ExifTag.YResolution, out ExifValue verticalTag) - ? ((Rational)verticalTag.Value).ToDouble() - : 0; + double horizontalValue = this.GetExifResolutionValue(ExifTag.XResolution); + double verticalValue = this.GetExifResolutionValue(ExifTag.YResolution); if (horizontalValue > 0 && verticalValue > 0) { @@ -480,6 +475,26 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } } + private double GetExifResolutionValue(ExifTag tag) + { + if (!this.MetaData.ExifProfile.TryGetValue(tag, out ExifValue exifValue)) + { + return 0; + } + + switch (exifValue.DataType) + { + case ExifDataType.Rational: + return ((Rational)exifValue.Value).ToDouble(); + case ExifDataType.Long: + return (uint)exifValue.Value; + case ExifDataType.DoubleFloat: + return (double)exifValue.Value; + default: + return 0; + } + } + /// /// Extends the profile with additional data. /// From bd4d5ba32d6c62109478fb961844b1a63c1b136a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 6 Sep 2018 21:47:49 +0100 Subject: [PATCH 046/185] Fix EXIF overflow and Jpeg decoding --- .../Formats/Jpeg/JpegDecoderCore.cs | 11 +++++---- .../MetaData/Profiles/Exif/ExifReader.cs | 24 ++++++++++--------- .../Formats/Jpg/JpegDecoderTests.Images.cs | 6 ++++- .../Formats/Jpg/JpegDecoderTests.cs | 2 ++ tests/ImageSharp.Tests/TestImages.cs | 3 +++ tests/Images/External | 2 +- .../Issue694-Decode-Exif-OutOfRange.jpg | 3 +++ .../Input/Jpg/issues/Issue695-Invalid-EOI.jpg | 3 +++ .../Issue696-Resize-Exif-OutOfRange.jpg | 3 +++ 9 files changed, 39 insertions(+), 18 deletions(-) create mode 100644 tests/Images/Input/Jpg/issues/Issue694-Decode-Exif-OutOfRange.jpg create mode 100644 tests/Images/Input/Jpg/issues/Issue695-Invalid-EOI.jpg create mode 100644 tests/Images/Input/Jpg/issues/Issue696-Resize-Exif-OutOfRange.jpg diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 7561afa1ef..057bd74bb4 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -268,7 +268,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.fastACTables = new FastACTables(this.configuration.MemoryAllocator); } - while (fileMarker.Marker != JpegConstants.Markers.EOI) + // Break only when we discover a valid EOI marker. + // https://github.com/SixLabors/ImageSharp/issues/695 + while (fileMarker.Marker != JpegConstants.Markers.EOI + || (fileMarker.Marker == JpegConstants.Markers.EOI && fileMarker.Invalid)) { if (!fileMarker.Invalid) { @@ -898,10 +901,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The codelengths /// The values [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void BuildHuffmanTable(HuffmanTables tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) - { - tables[index] = new HuffmanTable(this.configuration.MemoryAllocator, codeLengths, values); - } + private void BuildHuffmanTable(HuffmanTables tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) + => tables[index] = new HuffmanTable(this.configuration.MemoryAllocator, codeLengths, values); /// /// Reads a from the stream advancing it by two bytes diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 72db6305dd..549cb3fe09 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -88,19 +88,19 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } uint ifdOffset = this.ReadUInt32(); - this.AddValues(values, (int)ifdOffset); + this.AddValues(values, ifdOffset); uint thumbnailOffset = this.ReadUInt32(); - this.GetThumbnail((int)thumbnailOffset); + this.GetThumbnail(thumbnailOffset); if (this.exifOffset != 0) { - this.AddValues(values, (int)this.exifOffset); + this.AddValues(values, this.exifOffset); } if (this.gpsOffset != 0) { - this.AddValues(values, (int)this.gpsOffset); + this.AddValues(values, this.gpsOffset); } return values; @@ -153,9 +153,14 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// The values. /// The index. - private void AddValues(List values, int index) + private void AddValues(List values, uint index) { - this.position = index; + if (index > (uint)this.exifData.Length) + { + return; + } + + this.position = (int)index; int count = this.ReadUInt16(); for (int i = 0; i < count; i++) @@ -431,7 +436,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return null; } - private void GetThumbnail(int offset) + private void GetThumbnail(uint offset) { var values = new List(); this.AddValues(values, offset); @@ -515,10 +520,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return new Rational(numerator, denominator, false); } - private sbyte ConvertToSignedByte(ReadOnlySpan buffer) - { - return unchecked((sbyte)buffer[0]); - } + private sbyte ConvertToSignedByte(ReadOnlySpan buffer) => unchecked((sbyte)buffer[0]); private int ConvertToInt32(ReadOnlySpan buffer) // SignedLong in Exif Specification { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index 3c98d5be72..a14c4735f5 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -21,7 +21,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Baseline.Bad.BadEOF, TestImages.Jpeg.Issues.MultiHuffmanBaseline394, TestImages.Jpeg.Baseline.MultiScanBaselineCMYK, - TestImages.Jpeg.Baseline.Bad.BadRST + TestImages.Jpeg.Baseline.Bad.BadRST, + TestImages.Jpeg.Issues.MultiHuffmanBaseline394, + TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, + TestImages.Jpeg.Issues.InvalidEOI695, + TestImages.Jpeg.Issues.ExifResizeOutOfRange696 }; public static string[] ProgressiveTestJpegs = diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 4ae955c323..5977e59cf3 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -48,6 +48,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.BadZigZagProgressive385, TestImages.Jpeg.Issues.NoEoiProgressive517, TestImages.Jpeg.Issues.BadRstProgressive518, + TestImages.Jpeg.Issues.InvalidEOI695, + TestImages.Jpeg.Issues.ExifResizeOutOfRange696 }; return !TestEnvironment.Is64BitProcess && largeImagesToSkipOn32Bit.Contains(provider.SourceFileOrDescription); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1ee3f96757..0ad3edda88 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -152,6 +152,9 @@ namespace SixLabors.ImageSharp.Tests public const string BadRstProgressive518 = "Jpg/issues/Issue518-Bad-RST-Progressive.jpg"; public const string InvalidCast520 = "Jpg/issues/Issue520-InvalidCast.jpg"; public const string DhtHasWrongLength624 = "Jpg/issues/Issue624-DhtHasWrongLength-Progressive-N.jpg"; + public const string ExifDecodeOutOfRange694 = "Jpg/issues/Issue694-Decode-Exif-OutOfRange.jpg"; + public const string InvalidEOI695 = "Jpg/issues/Issue695-Invalid-EOI.jpg"; + public const string ExifResizeOutOfRange696 = "Jpg/issues/Issue696-Resize-Exif-OutOfRange.jpg"; } public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); diff --git a/tests/Images/External b/tests/Images/External index fcf311bf15..6abc3bc0ac 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit fcf311bf15bea061e552e4cc357cafe2d4f4bd70 +Subproject commit 6abc3bc0ac253a24c9e88e68d7b7d853350a85da diff --git a/tests/Images/Input/Jpg/issues/Issue694-Decode-Exif-OutOfRange.jpg b/tests/Images/Input/Jpg/issues/Issue694-Decode-Exif-OutOfRange.jpg new file mode 100644 index 0000000000..b3a7ce356c --- /dev/null +++ b/tests/Images/Input/Jpg/issues/Issue694-Decode-Exif-OutOfRange.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1b94a283fbe8927ab59745dd67d0b33e90a253e674e5fe4f0ad7594ff868cca2 +size 226421 diff --git a/tests/Images/Input/Jpg/issues/Issue695-Invalid-EOI.jpg b/tests/Images/Input/Jpg/issues/Issue695-Invalid-EOI.jpg new file mode 100644 index 0000000000..4891779878 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/Issue695-Invalid-EOI.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e748a684c318b7424dd77b008fe92e179201d0a55106021b453a3fd2a22e9ab6 +size 4805575 diff --git a/tests/Images/Input/Jpg/issues/Issue696-Resize-Exif-OutOfRange.jpg b/tests/Images/Input/Jpg/issues/Issue696-Resize-Exif-OutOfRange.jpg new file mode 100644 index 0000000000..38c5c8d59c --- /dev/null +++ b/tests/Images/Input/Jpg/issues/Issue696-Resize-Exif-OutOfRange.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bb22005e1db0f6da8f49ca57979f8b9aa5db7111b717a53e817e24c04283ab43 +size 3196058 From 1e3f4c5187719f4d28310bba6de0a545a3e6ee50 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 6 Sep 2018 22:21:16 +0100 Subject: [PATCH 047/185] Remove traililng whitespace --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 057bd74bb4..2219edef50 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -901,7 +901,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The codelengths /// The values [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void BuildHuffmanTable(HuffmanTables tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) + private void BuildHuffmanTable(HuffmanTables tables, int index, ReadOnlySpan codeLengths, ReadOnlySpan values) => tables[index] = new HuffmanTable(this.configuration.MemoryAllocator, codeLengths, values); /// From dc4ec30a14d82bd901ccb257a2de4277d0d52e80 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 7 Sep 2018 22:01:18 +0100 Subject: [PATCH 048/185] Strong type meta query + format singletons --- .../Formats/Bmp/BmpConfigurationModule.cs | 8 +-- src/ImageSharp/Formats/Bmp/BmpFormat.cs | 14 ++++-- .../Formats/Bmp/BmpImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 15 ++++++ src/ImageSharp/Formats/Bmp/ImageExtensions.cs | 2 +- .../Formats/Gif/GifConfigurationModule.cs | 9 ++-- src/ImageSharp/Formats/Gif/GifConstants.cs | 5 -- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 6 +-- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 6 +-- src/ImageSharp/Formats/Gif/GifFormat.cs | 14 ++++-- .../Formats/Gif/GifFrameMetaData.cs | 4 +- .../Formats/Gif/GifImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Gif/GifMetaData.cs | 4 +- .../Formats/Gif/GifMetaDataExtensions.cs | 49 ------------------- src/ImageSharp/Formats/Gif/ImageExtensions.cs | 2 +- src/ImageSharp/Formats/ImageFormatBase{T}.cs | 38 ++++++++++++++ .../Formats/Jpeg/ImageExtensions.cs | 2 +- .../Formats/Jpeg/JpegConfigurationModule.cs | 9 ++-- src/ImageSharp/Formats/Jpeg/JpegFormat.cs | 14 ++++-- .../Formats/Jpeg/JpegImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 15 ++++++ src/ImageSharp/Formats/Png/ImageExtensions.cs | 2 +- .../Formats/Png/PngConfigurationModule.cs | 4 +- src/ImageSharp/Formats/Png/PngFormat.cs | 14 ++++-- .../Formats/Png/PngImageFormatDetector.cs | 2 +- src/ImageSharp/Formats/Png/PngMetaData.cs | 15 ++++++ src/ImageSharp/ImageFormats.cs | 37 -------------- .../MetaData/IImageFormatFrameMetaData.cs | 13 +++++ .../MetaData/IImageFormatMetaData.cs | 13 +++++ src/ImageSharp/MetaData/ImageFrameMetaData.cs | 30 +++++------- src/ImageSharp/MetaData/ImageMetaData.cs | 30 +++++------- tests/ImageSharp.Tests/ConfigurationTests.cs | 13 ++--- .../Formats/GeneralFormatTests.cs | 2 +- .../Formats/Gif/GifEncoderTests.cs | 10 ++-- .../Formats/ImageFormatManagerTests.cs | 4 +- .../MetaData/ImageFrameMetaDataTests.cs | 4 +- .../TestUtilities/TestEnvironment.Formats.cs | 4 +- 37 files changed, 221 insertions(+), 198 deletions(-) create mode 100644 src/ImageSharp/Formats/Bmp/BmpMetaData.cs delete mode 100644 src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs create mode 100644 src/ImageSharp/Formats/ImageFormatBase{T}.cs create mode 100644 src/ImageSharp/Formats/Jpeg/JpegMetaData.cs create mode 100644 src/ImageSharp/Formats/Png/PngMetaData.cs delete mode 100644 src/ImageSharp/ImageFormats.cs create mode 100644 src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs create mode 100644 src/ImageSharp/MetaData/IImageFormatMetaData.cs diff --git a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs index 956acc1578..57117cc075 100644 --- a/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs +++ b/src/ImageSharp/Formats/Bmp/BmpConfigurationModule.cs @@ -9,11 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp public sealed class BmpConfigurationModule : IConfigurationModule { /// - public void Configure(Configuration config) + public void Configure(Configuration configuration) { - config.ImageFormatsManager.SetEncoder(ImageFormats.Bmp, new BmpEncoder()); - config.ImageFormatsManager.SetDecoder(ImageFormats.Bmp, new BmpDecoder()); - config.ImageFormatsManager.AddImageFormatDetector(new BmpImageFormatDetector()); + configuration.ImageFormatsManager.SetEncoder(BmpFormat.Instance, new BmpEncoder()); + configuration.ImageFormatsManager.SetDecoder(BmpFormat.Instance, new BmpDecoder()); + configuration.ImageFormatsManager.AddImageFormatDetector(new BmpImageFormatDetector()); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs index 64c6574c1e..de3f6f3f44 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs @@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Registers the image encoders, decoders and mime type detectors for the bmp format. /// - internal sealed class BmpFormat : IImageFormat + internal sealed class BmpFormat : ImageFormatBase { + private BmpFormat() + { + } + /// - public string Name => "BMP"; + public override string Name => "BMP"; /// - public string DefaultMimeType => "image/bmp"; + public override string DefaultMimeType => "image/bmp"; /// - public IEnumerable MimeTypes => BmpConstants.MimeTypes; + public override IEnumerable MimeTypes => BmpConstants.MimeTypes; /// - public IEnumerable FileExtensions => BmpConstants.FileExtensions; + public override IEnumerable FileExtensions => BmpConstants.FileExtensions; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs index bb884019b7..6a740d47d1 100644 --- a/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Bmp/BmpImageFormatDetector.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// public IImageFormat DetectFormat(ReadOnlySpan header) { - return this.IsSupportedFileFormat(header) ? ImageFormats.Bmp : null; + return this.IsSupportedFileFormat(header) ? BmpFormat.Instance : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs new file mode 100644 index 0000000000..1e350200a4 --- /dev/null +++ b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs @@ -0,0 +1,15 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData; + +namespace SixLabors.ImageSharp.Formats.Bmp +{ + /// + /// Provides Bmp specific metadata information for the image. + /// + public class BmpMetaData : IImageFormatMetaData + { + // TODO: Analyse what properties we would like to preserve. + } +} diff --git a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs index 57e4615bad..aa1c353db2 100644 --- a/src/ImageSharp/Formats/Bmp/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Bmp/ImageExtensions.cs @@ -34,6 +34,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsBmp(this Image source, Stream stream, BmpEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Bmp)); + => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(BmpFormat.Instance)); } } diff --git a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs index 0bb62779eb..861d3e0368 100644 --- a/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs +++ b/src/ImageSharp/Formats/Gif/GifConfigurationModule.cs @@ -9,12 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Gif public sealed class GifConfigurationModule : IConfigurationModule { /// - public void Configure(Configuration config) + public void Configure(Configuration configuration) { - config.ImageFormatsManager.SetEncoder(ImageFormats.Gif, new GifEncoder()); - config.ImageFormatsManager.SetDecoder(ImageFormats.Gif, new GifDecoder()); - - config.ImageFormatsManager.AddImageFormatDetector(new GifImageFormatDetector()); + configuration.ImageFormatsManager.SetEncoder(GifFormat.Instance, new GifEncoder()); + configuration.ImageFormatsManager.SetDecoder(GifFormat.Instance, new GifDecoder()); + configuration.ImageFormatsManager.AddImageFormatDetector(new GifImageFormatDetector()); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index cc80b0cce2..8167d0d2e0 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -26,11 +26,6 @@ namespace SixLabors.ImageSharp.Formats.Gif /// internal static readonly byte[] MagicNumber = Encoding.UTF8.GetBytes(FileType + FileVersion); - /// - /// Gets the key used for storing and retriving metadata. - /// - public const string MetaDataKey = FileType; - /// /// The extension block introducer !. /// diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 092ac859df..f503812641 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -164,7 +164,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.globalColorTable?.Dispose(); } - image?.MetaData.AddOrUpdateGifMetaData(this.gifMetaData); + image?.MetaData.AddOrUpdateFormatMetaData(GifFormat.Instance, this.gifMetaData); return image; } @@ -224,7 +224,7 @@ namespace SixLabors.ImageSharp.Formats.Gif this.globalColorTable?.Dispose(); } - this.metaData.AddOrUpdateGifMetaData(this.gifMetaData); + this.metaData.AddOrUpdateFormatMetaData(GifFormat.Instance, this.gifMetaData); return new ImageInfo( new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel), this.logicalScreenDescriptor.Width, @@ -561,7 +561,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } gifMeta.DisposalMethod = this.graphicsControlExtension.DisposalMethod; - meta.AddOrUpdateGifFrameMetaData(gifMeta); + meta.AddOrUpdateFormatMetaData(GifFormat.Instance, gifMeta); } /// diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index b373446589..20f2f1d336 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.gifMetaData = image.MetaData.GetGifMetaData() ?? new GifMetaData(); + this.gifMetaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; bool useGlobalTable = this.colorTableMode.Equals(GifColorTableMode.Global); @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Gif for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; - GifFrameMetaData frameMetaData = frame.MetaData.GetGifFrameMetaData() ?? new GifFrameMetaData(); + GifFrameMetaData frameMetaData = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); this.WriteGraphicalControlExtension(frameMetaData, transparencyIndex, stream); this.WriteImageDescriptor(frame, false, stream); @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp.Formats.Gif GifFrameMetaData previousMeta = null; foreach (ImageFrame frame in image.Frames) { - GifFrameMetaData meta = frame.MetaData.GetGifFrameMetaData() ?? new GifFrameMetaData(); + GifFrameMetaData meta = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs index 6353690f47..2d14abb444 100644 --- a/src/ImageSharp/Formats/Gif/GifFormat.cs +++ b/src/ImageSharp/Formats/Gif/GifFormat.cs @@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Registers the image encoders, decoders and mime type detectors for the gif format. /// - internal sealed class GifFormat : IImageFormat + internal sealed class GifFormat : ImageFormatBase { + private GifFormat() + { + } + /// - public string Name => "GIF"; + public override string Name => "GIF"; /// - public string DefaultMimeType => "image/gif"; + public override string DefaultMimeType => "image/gif"; /// - public IEnumerable MimeTypes => GifConstants.MimeTypes; + public override IEnumerable MimeTypes => GifConstants.MimeTypes; /// - public IEnumerable FileExtensions => GifConstants.FileExtensions; + public override IEnumerable FileExtensions => GifConstants.FileExtensions; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index cc04d48314..a7b68e6e85 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.MetaData; + namespace SixLabors.ImageSharp.Formats.Gif { /// /// Provides Gif specific metadata information for the image frame. /// - public class GifFrameMetaData + public class GifFrameMetaData : IImageFormatFrameMetaData { /// /// Gets or sets the length of the color table for paletted images. diff --git a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs index bfbd334b01..b8f9a03f1a 100644 --- a/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Gif/GifImageFormatDetector.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// public IImageFormat DetectFormat(ReadOnlySpan header) { - return this.IsSupportedFileFormat(header) ? ImageFormats.Gif : null; + return this.IsSupportedFileFormat(header) ? GifFormat.Instance : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs index f58f5dff3e..cc0716ec57 100644 --- a/src/ImageSharp/Formats/Gif/GifMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -1,12 +1,14 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.MetaData; + namespace SixLabors.ImageSharp.Formats.Gif { /// /// Provides Gif specific metadata information for the image. /// - public class GifMetaData + public class GifMetaData : IImageFormatMetaData { /// /// Gets or sets the number of times any animation is repeated. diff --git a/src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs b/src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs deleted file mode 100644 index 04b542d2d6..0000000000 --- a/src/ImageSharp/Formats/Gif/GifMetaDataExtensions.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.ImageSharp.MetaData; - -namespace SixLabors.ImageSharp.Formats.Gif -{ - /// - /// Extension methods for storing meta data specific to Gif images. - /// - public static class GifMetaDataExtensions - { - /// - /// Adds or updates the Gif specific meta data to the image. - /// - /// The image meta data. - /// The gif meta data. - public static void AddOrUpdateGifMetaData(this ImageMetaData meta, GifMetaData value) => meta.AddOrUpdateMetaData(GifConstants.MetaDataKey, value); - - /// - /// Gets the Gif format specific meta data from the image. - /// - /// The image meta data. - /// The or null. - public static GifMetaData GetGifMetaData(this ImageMetaData meta) - { - meta.TryGetMetaData(GifConstants.MetaDataKey, out GifMetaData value); - return value; - } - - /// - /// Adds or updates the Gif specific meta data to the image frame. - /// - /// The image meta data. - /// The gif meta data. - public static void AddOrUpdateGifFrameMetaData(this ImageFrameMetaData meta, GifFrameMetaData value) => meta.AddOrUpdateMetaData(GifConstants.MetaDataKey, value); - - /// - /// Gets the Gif format specific meta data from the image frame. - /// - /// The image meta data. - /// The or null. - public static GifFrameMetaData GetGifFrameMetaData(this ImageFrameMetaData meta) - { - meta.TryGetMetaData(GifConstants.MetaDataKey, out GifFrameMetaData value); - return value; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/ImageExtensions.cs b/src/ImageSharp/Formats/Gif/ImageExtensions.cs index 1c41285a97..8ddd4247e1 100644 --- a/src/ImageSharp/Formats/Gif/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Gif/ImageExtensions.cs @@ -34,6 +34,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsGif(this Image source, Stream stream, GifEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Gif)); + => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(GifFormat.Instance)); } } diff --git a/src/ImageSharp/Formats/ImageFormatBase{T}.cs b/src/ImageSharp/Formats/ImageFormatBase{T}.cs new file mode 100644 index 0000000000..85273db2be --- /dev/null +++ b/src/ImageSharp/Formats/ImageFormatBase{T}.cs @@ -0,0 +1,38 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Collections.Generic; + +namespace SixLabors.ImageSharp.Formats +{ + /// + /// The base class for all image formats. + /// Inheriting classes should implement the singleton pattern by creating a private constructor. + /// + /// The type of image format. + public abstract class ImageFormatBase : IImageFormat + where T : class, IImageFormat + { + private static readonly Lazy Lazy = new Lazy(CreateInstance); + + /// + /// Gets the current instance. + /// + public static T Instance => Lazy.Value; + + /// + public abstract string Name { get; } + + /// + public abstract string DefaultMimeType { get; } + + /// + public abstract IEnumerable MimeTypes { get; } + + /// + public abstract IEnumerable FileExtensions { get; } + + private static T CreateInstance() => (T)Activator.CreateInstance(typeof(T), true); + } +} diff --git a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs index 1d3be063dd..cb7fc19446 100644 --- a/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/ImageExtensions.cs @@ -34,6 +34,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsJpeg(this Image source, Stream stream, JpegEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Jpeg)); + => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(JpegFormat.Instance)); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs index c3bf801ac8..9840a2ae88 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegConfigurationModule.cs @@ -9,12 +9,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg public sealed class JpegConfigurationModule : IConfigurationModule { /// - public void Configure(Configuration config) + public void Configure(Configuration configuration) { - config.ImageFormatsManager.SetEncoder(ImageFormats.Jpeg, new JpegEncoder()); - config.ImageFormatsManager.SetDecoder(ImageFormats.Jpeg, new JpegDecoder()); - - config.ImageFormatsManager.AddImageFormatDetector(new JpegImageFormatDetector()); + configuration.ImageFormatsManager.SetEncoder(JpegFormat.Instance, new JpegEncoder()); + configuration.ImageFormatsManager.SetDecoder(JpegFormat.Instance, new JpegDecoder()); + configuration.ImageFormatsManager.AddImageFormatDetector(new JpegImageFormatDetector()); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs index 9a18f14d30..21757dcb3d 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs @@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// - internal sealed class JpegFormat : IImageFormat + internal sealed class JpegFormat : ImageFormatBase { + private JpegFormat() + { + } + /// - public string Name => "JPEG"; + public override string Name => "JPEG"; /// - public string DefaultMimeType => "image/jpeg"; + public override string DefaultMimeType => "image/jpeg"; /// - public IEnumerable MimeTypes => JpegConstants.MimeTypes; + public override IEnumerable MimeTypes => JpegConstants.MimeTypes; /// - public IEnumerable FileExtensions => JpegConstants.FileExtensions; + public override IEnumerable FileExtensions => JpegConstants.FileExtensions; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs index e25957efcf..7594f44770 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegImageFormatDetector.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// public IImageFormat DetectFormat(ReadOnlySpan header) { - return this.IsSupportedFileFormat(header) ? ImageFormats.Jpeg : null; + return this.IsSupportedFileFormat(header) ? JpegFormat.Instance : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs new file mode 100644 index 0000000000..eec0efa809 --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs @@ -0,0 +1,15 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData; + +namespace SixLabors.ImageSharp.Formats.Jpeg +{ + /// + /// Provides Jpeg specific metadata information for the image. + /// + public class JpegMetaData : IImageFormatMetaData + { + // TODO: Analyse what properties we would like to preserve. + } +} diff --git a/src/ImageSharp/Formats/Png/ImageExtensions.cs b/src/ImageSharp/Formats/Png/ImageExtensions.cs index a65845e02d..c73ec6f57e 100644 --- a/src/ImageSharp/Formats/Png/ImageExtensions.cs +++ b/src/ImageSharp/Formats/Png/ImageExtensions.cs @@ -35,6 +35,6 @@ namespace SixLabors.ImageSharp /// Thrown if the stream is null. public static void SaveAsPng(this Image source, Stream stream, PngEncoder encoder) where TPixel : struct, IPixel - => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(ImageFormats.Png)); + => source.Save(stream, encoder ?? source.GetConfiguration().ImageFormatsManager.FindEncoder(PngFormat.Instance)); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs index 64dad23bca..3c9fddbad4 100644 --- a/src/ImageSharp/Formats/Png/PngConfigurationModule.cs +++ b/src/ImageSharp/Formats/Png/PngConfigurationModule.cs @@ -11,8 +11,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// public void Configure(Configuration configuration) { - configuration.ImageFormatsManager.SetEncoder(ImageFormats.Png, new PngEncoder()); - configuration.ImageFormatsManager.SetDecoder(ImageFormats.Png, new PngDecoder()); + configuration.ImageFormatsManager.SetEncoder(PngFormat.Instance, new PngEncoder()); + configuration.ImageFormatsManager.SetDecoder(PngFormat.Instance, new PngDecoder()); configuration.ImageFormatsManager.AddImageFormatDetector(new PngImageFormatDetector()); } } diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs index 142f660712..00ebbde527 100644 --- a/src/ImageSharp/Formats/Png/PngFormat.cs +++ b/src/ImageSharp/Formats/Png/PngFormat.cs @@ -8,18 +8,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Registers the image encoders, decoders and mime type detectors for the png format. /// - internal sealed class PngFormat : IImageFormat + internal sealed class PngFormat : ImageFormatBase { + private PngFormat() + { + } + /// - public string Name => "PNG"; + public override string Name => "PNG"; /// - public string DefaultMimeType => "image/png"; + public override string DefaultMimeType => "image/png"; /// - public IEnumerable MimeTypes => PngConstants.MimeTypes; + public override IEnumerable MimeTypes => PngConstants.MimeTypes; /// - public IEnumerable FileExtensions => PngConstants.FileExtensions; + public override IEnumerable FileExtensions => PngConstants.FileExtensions; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs index c1c039a1be..5deed86e30 100644 --- a/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs +++ b/src/ImageSharp/Formats/Png/PngImageFormatDetector.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// public IImageFormat DetectFormat(ReadOnlySpan header) { - return this.IsSupportedFileFormat(header) ? ImageFormats.Png : null; + return this.IsSupportedFileFormat(header) ? PngFormat.Instance : null; } private bool IsSupportedFileFormat(ReadOnlySpan header) diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs new file mode 100644 index 0000000000..1d76cf580a --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -0,0 +1,15 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.MetaData; + +namespace SixLabors.ImageSharp.Formats.Png +{ + /// + /// Provides Png specific metadata information for the image. + /// + public class PngMetaData : IImageFormatMetaData + { + // TODO: Analyse what properties we would like to preserve. + } +} diff --git a/src/ImageSharp/ImageFormats.cs b/src/ImageSharp/ImageFormats.cs deleted file mode 100644 index bc437e5a5e..0000000000 --- a/src/ImageSharp/ImageFormats.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Formats.Bmp; -using SixLabors.ImageSharp.Formats.Gif; -using SixLabors.ImageSharp.Formats.Jpeg; -using SixLabors.ImageSharp.Formats.Png; - -namespace SixLabors.ImageSharp -{ - /// - /// The static collection of all the default image formats - /// - public static class ImageFormats - { - /// - /// The format details for the jpegs. - /// - public static readonly IImageFormat Jpeg = new JpegFormat(); - - /// - /// The format details for the pngs. - /// - public static readonly IImageFormat Png = new PngFormat(); - - /// - /// The format details for the gifs. - /// - public static readonly IImageFormat Gif = new GifFormat(); - - /// - /// The format details for the bitmaps. - /// - public static readonly IImageFormat Bmp = new BmpFormat(); - } -} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs b/src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs new file mode 100644 index 0000000000..5df6fa433d --- /dev/null +++ b/src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs @@ -0,0 +1,13 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.MetaData +{ + /// + /// Encapsulates the format specific metadata of an image frame. + /// This interface exists to allow type saftey and avoid the performance overhead of parsing attributes. + /// + public interface IImageFormatFrameMetaData + { + } +} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/IImageFormatMetaData.cs b/src/ImageSharp/MetaData/IImageFormatMetaData.cs new file mode 100644 index 0000000000..ded8df8013 --- /dev/null +++ b/src/ImageSharp/MetaData/IImageFormatMetaData.cs @@ -0,0 +1,13 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.MetaData +{ + /// + /// Encapsulates the format specific metadata of an image. + /// This interface exists to allow type saftey and avoid the performance overhead of parsing attributes. + /// + public interface IImageFormatMetaData + { + } +} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 55678789e5..31bad29b81 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.MetaData { @@ -11,7 +12,7 @@ namespace SixLabors.ImageSharp.MetaData /// public sealed class ImageFrameMetaData { - private readonly Dictionary metaData = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary metaData = new Dictionary(); /// /// Initializes a new instance of the class. @@ -31,7 +32,7 @@ namespace SixLabors.ImageSharp.MetaData { DebugGuard.NotNull(other, nameof(other)); - foreach (KeyValuePair meta in other.metaData) + foreach (KeyValuePair meta in other.metaData) { this.metaData.Add(meta.Key, meta.Value); } @@ -51,7 +52,7 @@ namespace SixLabors.ImageSharp.MetaData /// key is null. /// value is null. /// An element with the same key already exists in the . - public void AddOrUpdateMetaData(string key, object value) + public void AddOrUpdateFormatMetaData(IImageFormat key, IImageFormatFrameMetaData value) { // Don't think this needs to be threadsafe. Guard.NotNull(value, nameof(value)); @@ -61,27 +62,22 @@ namespace SixLabors.ImageSharp.MetaData /// /// Gets the metadata value associated with the specified key. /// - /// The type of value. + /// The type of metadata. /// The key of the value to get. - /// - /// When this method returns, contains the metadata value associated with the specified key, - /// if the key is found; otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// /// - /// true if the contains an element with - /// the specified key; otherwise, false. + /// The . /// - public bool TryGetMetaData(string key, out T value) + public T GetOrAddFormatMetaData(IImageFormat key) + where T : IImageFormatFrameMetaData, new() { - if (this.metaData.TryGetValue(key, out object meta)) + if (this.metaData.TryGetValue(key, out IImageFormatFrameMetaData meta)) { - value = (T)meta; - return true; + return (T)meta; } - value = default; - return false; + var newMeta = new T(); + this.AddOrUpdateFormatMetaData(key, newMeta); + return newMeta; } } } \ No newline at end of file diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 8233798c22..d907e8b8a5 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.MetaData.Profiles.Icc; @@ -25,7 +26,7 @@ namespace SixLabors.ImageSharp.MetaData /// public const double DefaultVerticalResolution = 96; - private readonly Dictionary metaData = new Dictionary(StringComparer.OrdinalIgnoreCase); + private readonly Dictionary metaData = new Dictionary(); private double horizontalResolution; private double verticalResolution; @@ -51,7 +52,7 @@ namespace SixLabors.ImageSharp.MetaData this.VerticalResolution = other.VerticalResolution; this.ResolutionUnits = other.ResolutionUnits; - foreach (KeyValuePair meta in other.metaData) + foreach (KeyValuePair meta in other.metaData) { this.metaData.Add(meta.Key, meta.Value); } @@ -138,7 +139,7 @@ namespace SixLabors.ImageSharp.MetaData /// key is null. /// value is null. /// An element with the same key already exists in the . - public void AddOrUpdateMetaData(string key, object value) + public void AddOrUpdateFormatMetaData(IImageFormat key, IImageFormatMetaData value) { // Don't think this needs to be threadsafe. Guard.NotNull(value, nameof(value)); @@ -148,27 +149,22 @@ namespace SixLabors.ImageSharp.MetaData /// /// Gets the metadata value associated with the specified key. /// - /// The type of value. + /// The type of metadata. /// The key of the value to get. - /// - /// When this method returns, contains the metadata value associated with the specified key, - /// if the key is found; otherwise, the default value for the type of the value parameter. - /// This parameter is passed uninitialized. - /// /// - /// true if the contains an element with - /// the specified key; otherwise, false. + /// The . /// - public bool TryGetMetaData(string key, out T value) + public T GetOrAddFormatMetaData(IImageFormat key) + where T : IImageFormatMetaData, new() { - if (this.metaData.TryGetValue(key, out object meta)) + if (this.metaData.TryGetValue(key, out IImageFormatMetaData meta)) { - value = (T)meta; - return true; + return (T)meta; } - value = default; - return false; + var newMeta = new T(); + this.AddOrUpdateFormatMetaData(key, newMeta); + return newMeta; } /// diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 4bec25f7a2..6a8479b2b2 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -4,6 +4,7 @@ using System; using System.Linq; using Moq; +using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.IO; using Xunit; // ReSharper disable InconsistentNaming @@ -37,19 +38,13 @@ namespace SixLabors.ImageSharp.Tests /// Test that the default configuration is not null. /// [Fact] - public void TestDefaultConfigurationIsNotNull() - { - Assert.True(Configuration.Default != null); - } + public void TestDefaultConfigurationIsNotNull() => Assert.True(Configuration.Default != null); /// /// Test that the default configuration read origin options is set to begin. /// [Fact] - public void TestDefaultConfigurationReadOriginIsCurrent() - { - Assert.True(Configuration.Default.ReadOrigin == ReadOrigin.Current); - } + public void TestDefaultConfigurationReadOriginIsCurrent() => Assert.True(Configuration.Default.ReadOrigin == ReadOrigin.Current); /// /// Test that the default configuration parallel options max degrees of parallelism matches the @@ -101,7 +96,7 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(count, config.ImageFormats.Count()); - config.ImageFormatsManager.AddImageFormat(ImageFormats.Bmp); + config.ImageFormatsManager.AddImageFormat(BmpFormat.Instance); Assert.Equal(count, config.ImageFormats.Count()); } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 23b806767c..f8b035ca83 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Tests using (Image image = file.CreateImage()) { string filename = path + "/" + file.FileNameWithoutExtension + ".txt"; - File.WriteAllText(filename, image.ToBase64String(ImageFormats.Png)); + File.WriteAllText(filename, image.ToBase64String(PngFormat.Instance)); } } } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 2b08bf20de..4ddcded5ea 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -189,8 +189,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif inStream.Position = 0; var image = Image.Load(inStream); - GifMetaData metaData = image.MetaData.GetGifMetaData(); - GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetGifFrameMetaData(); + GifMetaData metaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); GifColorTableMode colorMode = metaData.ColorTableMode; var encoder = new GifEncoder() { @@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif outStream.Position = 0; var clone = Image.Load(outStream); - GifMetaData cloneMetaData = clone.MetaData.GetGifMetaData(); + GifMetaData cloneMetaData = clone.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); Assert.Equal(metaData.ColorTableMode, cloneMetaData.ColorTableMode); // Gifiddle and Cyotek GifInfo say this image has 64 colors. @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif for (int i = 0; i < image.Frames.Count; i++) { - GifFrameMetaData ifm = image.Frames[i].MetaData.GetGifFrameMetaData(); - GifFrameMetaData cifm = clone.Frames[i].MetaData.GetGifFrameMetaData(); + GifFrameMetaData ifm = image.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData cifm = clone.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); Assert.Equal(ifm.ColorTableLength, cifm.ColorTableLength); Assert.Equal(ifm.FrameDelay, cifm.FrameDelay); diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs index f10a4ce842..464b1564b8 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Tests }); Assert.Throws(() => { - this.DefaultFormatsManager.SetEncoder(ImageFormats.Bmp, null); + this.DefaultFormatsManager.SetEncoder(BmpFormat.Instance, null); }); Assert.Throws(() => { @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Tests }); Assert.Throws(() => { - this.DefaultFormatsManager.SetDecoder(ImageFormats.Bmp, null); + this.DefaultFormatsManager.SetDecoder(BmpFormat.Instance, null); }); Assert.Throws(() => { diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index c250d973b5..00d03dce4c 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -27,10 +27,10 @@ namespace SixLabors.ImageSharp.Tests }; var metaData = new ImageFrameMetaData(); - metaData.AddOrUpdateGifFrameMetaData(gifFrameMetaData); + metaData.AddOrUpdateFormatMetaData(GifFormat.Instance, gifFrameMetaData); var clone = new ImageFrameMetaData(metaData); - GifFrameMetaData cloneGifFrameMetaData = clone.GetGifFrameMetaData(); + GifFrameMetaData cloneGifFrameMetaData = clone.GetOrAddFormatMetaData(GifFormat.Instance); Assert.Equal(frameDelay, cloneGifFrameMetaData.FrameDelay); Assert.Equal(colorTableLength, cloneGifFrameMetaData.ColorTableLength); diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 90c999f7cd..334b6552ac 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -62,13 +62,13 @@ namespace SixLabors.ImageSharp.Tests IImageEncoder bmpEncoder = IsWindows ? (IImageEncoder)SystemDrawingReferenceEncoder.Bmp : new BmpEncoder(); cfg.ConfigureCodecs( - ImageFormats.Png, + PngFormat.Instance, MagickReferenceDecoder.Instance, pngEncoder, new PngImageFormatDetector()); cfg.ConfigureCodecs( - ImageFormats.Bmp, + BmpFormat.Instance, SystemDrawingReferenceDecoder.Instance, bmpEncoder, new BmpImageFormatDetector()); From 9f5fd5605bb09094011952bb0f964f4c7759990c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 9 Sep 2018 20:42:53 +0100 Subject: [PATCH 049/185] Much better type safety. --- src/ImageSharp/Formats/Bmp/BmpFormat.cs | 18 ++++++--- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 4 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 4 +- src/ImageSharp/Formats/Gif/GifFormat.cs | 21 +++++++--- .../Formats/Gif/GifFrameMetaData.cs | 4 +- src/ImageSharp/Formats/Gif/GifMetaData.cs | 4 +- src/ImageSharp/Formats/IImageFormat.cs | 32 +++++++++++++++- src/ImageSharp/Formats/ImageFormatBase{T}.cs | 38 ------------------- src/ImageSharp/Formats/Jpeg/JpegFormat.cs | 18 ++++++--- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 4 +- src/ImageSharp/Formats/Png/PngFormat.cs | 18 ++++++--- src/ImageSharp/Formats/Png/PngMetaData.cs | 4 +- .../MetaData/IImageFormatFrameMetaData.cs | 13 ------- .../MetaData/IImageFormatMetaData.cs | 13 ------- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 26 ++++++++----- src/ImageSharp/MetaData/ImageMetaData.cs | 22 ++++++----- .../Formats/Gif/GifEncoderTests.cs | 8 ++-- .../MetaData/ImageFrameMetaDataTests.cs | 2 +- 18 files changed, 126 insertions(+), 127 deletions(-) delete mode 100644 src/ImageSharp/Formats/ImageFormatBase{T}.cs delete mode 100644 src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs delete mode 100644 src/ImageSharp/MetaData/IImageFormatMetaData.cs diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs index de3f6f3f44..665f492daf 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs @@ -8,22 +8,30 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Registers the image encoders, decoders and mime type detectors for the bmp format. /// - internal sealed class BmpFormat : ImageFormatBase + internal sealed class BmpFormat : IImageFormat { private BmpFormat() { } + /// + /// Gets the current instance. + /// + public static BmpFormat Instance { get; } = new BmpFormat(); + + /// + public string Name => "BMP"; + /// - public override string Name => "BMP"; + public string DefaultMimeType => "image/bmp"; /// - public override string DefaultMimeType => "image/bmp"; + public IEnumerable MimeTypes => BmpConstants.MimeTypes; /// - public override IEnumerable MimeTypes => BmpConstants.MimeTypes; + public IEnumerable FileExtensions => BmpConstants.FileExtensions; /// - public override IEnumerable FileExtensions => BmpConstants.FileExtensions; + public BmpMetaData CreateDefaultFormatMetaData() => new BmpMetaData(); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs index 1e350200a4..aa60f38662 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs @@ -1,14 +1,12 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.MetaData; - namespace SixLabors.ImageSharp.Formats.Bmp { /// /// Provides Bmp specific metadata information for the image. /// - public class BmpMetaData : IImageFormatMetaData + public class BmpMetaData { // TODO: Analyse what properties we would like to preserve. } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 20f2f1d336..7a880b0f96 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Gif for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; - GifFrameMetaData frameMetaData = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData frameMetaData = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); this.WriteGraphicalControlExtension(frameMetaData, transparencyIndex, stream); this.WriteImageDescriptor(frame, false, stream); @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp.Formats.Gif GifFrameMetaData previousMeta = null; foreach (ImageFrame frame in image.Frames) { - GifFrameMetaData meta = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData meta = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs index 2d14abb444..f91269ceda 100644 --- a/src/ImageSharp/Formats/Gif/GifFormat.cs +++ b/src/ImageSharp/Formats/Gif/GifFormat.cs @@ -8,22 +8,33 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Registers the image encoders, decoders and mime type detectors for the gif format. /// - internal sealed class GifFormat : ImageFormatBase + internal sealed class GifFormat : IImageFormat { private GifFormat() { } + /// + /// Gets the current instance. + /// + public static GifFormat Instance { get; } = new GifFormat(); + + /// + public string Name => "GIF"; + + /// + public string DefaultMimeType => "image/gif"; + /// - public override string Name => "GIF"; + public IEnumerable MimeTypes => GifConstants.MimeTypes; /// - public override string DefaultMimeType => "image/gif"; + public IEnumerable FileExtensions => GifConstants.FileExtensions; /// - public override IEnumerable MimeTypes => GifConstants.MimeTypes; + public GifMetaData CreateDefaultFormatMetaData() => new GifMetaData(); /// - public override IEnumerable FileExtensions => GifConstants.FileExtensions; + public GifFrameMetaData CreateDefaultFormatFrameMetaData() => new GifFrameMetaData(); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index a7b68e6e85..cc04d48314 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -1,14 +1,12 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.MetaData; - namespace SixLabors.ImageSharp.Formats.Gif { /// /// Provides Gif specific metadata information for the image frame. /// - public class GifFrameMetaData : IImageFormatFrameMetaData + public class GifFrameMetaData { /// /// Gets or sets the length of the color table for paletted images. diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs index cc0716ec57..f58f5dff3e 100644 --- a/src/ImageSharp/Formats/Gif/GifMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -1,14 +1,12 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.MetaData; - namespace SixLabors.ImageSharp.Formats.Gif { /// /// Provides Gif specific metadata information for the image. /// - public class GifMetaData : IImageFormatMetaData + public class GifMetaData { /// /// Gets or sets the number of times any animation is repeated. diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index 15bdc73a84..9720352750 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -6,7 +6,37 @@ using System.Collections.Generic; namespace SixLabors.ImageSharp.Formats { /// - /// Describes an image format. + /// Defines the contract for an image format containing metadata with multiple frames. + /// + /// The type of format metadata. + /// The type of format frame metadata. + public interface IImageFormat : IImageFormat + where TFormatMetaData : class + where TFormatFrameMetaData : class + { + /// + /// Creates a default instance of the format frame metadata. + /// + /// The . + TFormatFrameMetaData CreateDefaultFormatFrameMetaData(); + } + + /// + /// Defines the contract for an image format containing metadata. + /// + /// The type of format metadata. + public interface IImageFormat : IImageFormat + where TFormatMetaData : class + { + /// + /// Creates a default instance of the format metadata. + /// + /// The . + TFormatMetaData CreateDefaultFormatMetaData(); + } + + /// + /// Defines the contract for an image format. /// public interface IImageFormat { diff --git a/src/ImageSharp/Formats/ImageFormatBase{T}.cs b/src/ImageSharp/Formats/ImageFormatBase{T}.cs deleted file mode 100644 index 85273db2be..0000000000 --- a/src/ImageSharp/Formats/ImageFormatBase{T}.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Collections.Generic; - -namespace SixLabors.ImageSharp.Formats -{ - /// - /// The base class for all image formats. - /// Inheriting classes should implement the singleton pattern by creating a private constructor. - /// - /// The type of image format. - public abstract class ImageFormatBase : IImageFormat - where T : class, IImageFormat - { - private static readonly Lazy Lazy = new Lazy(CreateInstance); - - /// - /// Gets the current instance. - /// - public static T Instance => Lazy.Value; - - /// - public abstract string Name { get; } - - /// - public abstract string DefaultMimeType { get; } - - /// - public abstract IEnumerable MimeTypes { get; } - - /// - public abstract IEnumerable FileExtensions { get; } - - private static T CreateInstance() => (T)Activator.CreateInstance(typeof(T), true); - } -} diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs index 21757dcb3d..94c0895b9d 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs @@ -8,22 +8,30 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// - internal sealed class JpegFormat : ImageFormatBase + internal sealed class JpegFormat : IImageFormat { private JpegFormat() { } + /// + /// Gets the current instance. + /// + public static JpegFormat Instance { get; } = new JpegFormat(); + + /// + public string Name => "JPEG"; + /// - public override string Name => "JPEG"; + public string DefaultMimeType => "image/jpeg"; /// - public override string DefaultMimeType => "image/jpeg"; + public IEnumerable MimeTypes => JpegConstants.MimeTypes; /// - public override IEnumerable MimeTypes => JpegConstants.MimeTypes; + public IEnumerable FileExtensions => JpegConstants.FileExtensions; /// - public override IEnumerable FileExtensions => JpegConstants.FileExtensions; + public JpegMetaData CreateDefaultFormatMetaData() => new JpegMetaData(); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs index eec0efa809..b05f9fa15a 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs @@ -1,14 +1,12 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.MetaData; - namespace SixLabors.ImageSharp.Formats.Jpeg { /// /// Provides Jpeg specific metadata information for the image. /// - public class JpegMetaData : IImageFormatMetaData + public class JpegMetaData { // TODO: Analyse what properties we would like to preserve. } diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs index 00ebbde527..b5223cb5a8 100644 --- a/src/ImageSharp/Formats/Png/PngFormat.cs +++ b/src/ImageSharp/Formats/Png/PngFormat.cs @@ -8,22 +8,30 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Registers the image encoders, decoders and mime type detectors for the png format. /// - internal sealed class PngFormat : ImageFormatBase + internal sealed class PngFormat : IImageFormat { private PngFormat() { } + /// + /// Gets the current instance. + /// + public static PngFormat Instance { get; } = new PngFormat(); + + /// + public string Name => "PNG"; + /// - public override string Name => "PNG"; + public string DefaultMimeType => "image/png"; /// - public override string DefaultMimeType => "image/png"; + public IEnumerable MimeTypes => PngConstants.MimeTypes; /// - public override IEnumerable MimeTypes => PngConstants.MimeTypes; + public IEnumerable FileExtensions => PngConstants.FileExtensions; /// - public override IEnumerable FileExtensions => PngConstants.FileExtensions; + public PngMetaData CreateDefaultFormatMetaData() => new PngMetaData(); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 1d76cf580a..90dbb83b6f 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -1,14 +1,12 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.MetaData; - namespace SixLabors.ImageSharp.Formats.Png { /// /// Provides Png specific metadata information for the image. /// - public class PngMetaData : IImageFormatMetaData + public class PngMetaData { // TODO: Analyse what properties we would like to preserve. } diff --git a/src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs b/src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs deleted file mode 100644 index 5df6fa433d..0000000000 --- a/src/ImageSharp/MetaData/IImageFormatFrameMetaData.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.MetaData -{ - /// - /// Encapsulates the format specific metadata of an image frame. - /// This interface exists to allow type saftey and avoid the performance overhead of parsing attributes. - /// - public interface IImageFormatFrameMetaData - { - } -} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/IImageFormatMetaData.cs b/src/ImageSharp/MetaData/IImageFormatMetaData.cs deleted file mode 100644 index ded8df8013..0000000000 --- a/src/ImageSharp/MetaData/IImageFormatMetaData.cs +++ /dev/null @@ -1,13 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.MetaData -{ - /// - /// Encapsulates the format specific metadata of an image. - /// This interface exists to allow type saftey and avoid the performance overhead of parsing attributes. - /// - public interface IImageFormatMetaData - { - } -} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 31bad29b81..07d4bdb05e 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.MetaData /// public sealed class ImageFrameMetaData { - private readonly Dictionary metaData = new Dictionary(); + private readonly Dictionary metaData = new Dictionary(); /// /// Initializes a new instance of the class. @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.MetaData { DebugGuard.NotNull(other, nameof(other)); - foreach (KeyValuePair meta in other.metaData) + foreach (KeyValuePair meta in other.metaData) { this.metaData.Add(meta.Key, meta.Value); } @@ -47,12 +47,16 @@ namespace SixLabors.ImageSharp.MetaData /// /// Adds or updates the specified key and value to the . /// + /// The type of format metadata. + /// The type of format frame metadata. /// The key of the metadata to add. /// The value of the element to add. /// key is null. /// value is null. /// An element with the same key already exists in the . - public void AddOrUpdateFormatMetaData(IImageFormat key, IImageFormatFrameMetaData value) + public void AddOrUpdateFormatMetaData(IImageFormat key, TFormatFrameMetaData value) + where TFormatMetaData : class + where TFormatFrameMetaData : class { // Don't think this needs to be threadsafe. Guard.NotNull(value, nameof(value)); @@ -62,20 +66,22 @@ namespace SixLabors.ImageSharp.MetaData /// /// Gets the metadata value associated with the specified key. /// - /// The type of metadata. + /// The type of format metadata. + /// The type of format frame metadata. /// The key of the value to get. /// - /// The . + /// The . /// - public T GetOrAddFormatMetaData(IImageFormat key) - where T : IImageFormatFrameMetaData, new() + public TFormatFrameMetaData GetOrAddFormatMetaData(IImageFormat key) + where TFormatMetaData : class + where TFormatFrameMetaData : class { - if (this.metaData.TryGetValue(key, out IImageFormatFrameMetaData meta)) + if (this.metaData.TryGetValue(key, out object meta)) { - return (T)meta; + return (TFormatFrameMetaData)meta; } - var newMeta = new T(); + TFormatFrameMetaData newMeta = key.CreateDefaultFormatFrameMetaData(); this.AddOrUpdateFormatMetaData(key, newMeta); return newMeta; } diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index d907e8b8a5..aa084728ca 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.MetaData /// public const double DefaultVerticalResolution = 96; - private readonly Dictionary metaData = new Dictionary(); + private readonly Dictionary metaData = new Dictionary(); private double horizontalResolution; private double verticalResolution; @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.MetaData this.VerticalResolution = other.VerticalResolution; this.ResolutionUnits = other.ResolutionUnits; - foreach (KeyValuePair meta in other.metaData) + foreach (KeyValuePair meta in other.metaData) { this.metaData.Add(meta.Key, meta.Value); } @@ -134,12 +134,14 @@ namespace SixLabors.ImageSharp.MetaData /// /// Adds or updates the specified key and value to the . /// + /// The type of format metadata. /// The key of the metadata to add. /// The value of the element to add. /// key is null. /// value is null. /// An element with the same key already exists in the . - public void AddOrUpdateFormatMetaData(IImageFormat key, IImageFormatMetaData value) + public void AddOrUpdateFormatMetaData(IImageFormat key, TFormatMetaData value) + where TFormatMetaData : class { // Don't think this needs to be threadsafe. Guard.NotNull(value, nameof(value)); @@ -149,20 +151,20 @@ namespace SixLabors.ImageSharp.MetaData /// /// Gets the metadata value associated with the specified key. /// - /// The type of metadata. + /// The type of metadata. /// The key of the value to get. /// - /// The . + /// The . /// - public T GetOrAddFormatMetaData(IImageFormat key) - where T : IImageFormatMetaData, new() + public TFormatMetaData GetOrAddFormatMetaData(IImageFormat key) + where TFormatMetaData : class { - if (this.metaData.TryGetValue(key, out IImageFormatMetaData meta)) + if (this.metaData.TryGetValue(key, out object meta)) { - return (T)meta; + return (TFormatMetaData)meta; } - var newMeta = new T(); + TFormatMetaData newMeta = key.CreateDefaultFormatMetaData(); this.AddOrUpdateFormatMetaData(key, newMeta); return newMeta; } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 4ddcded5ea..0c32689f09 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -189,8 +189,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif inStream.Position = 0; var image = Image.Load(inStream); - GifMetaData metaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); - GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifMetaData metaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); GifColorTableMode colorMode = metaData.ColorTableMode; var encoder = new GifEncoder() { @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif for (int i = 0; i < image.Frames.Count; i++) { - GifFrameMetaData ifm = image.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); - GifFrameMetaData cifm = clone.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData ifm = image.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData cifm = clone.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); Assert.Equal(ifm.ColorTableLength, cifm.ColorTableLength); Assert.Equal(ifm.FrameDelay, cifm.FrameDelay); diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 00d03dce4c..54441f0cbf 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp.Tests metaData.AddOrUpdateFormatMetaData(GifFormat.Instance, gifFrameMetaData); var clone = new ImageFrameMetaData(metaData); - GifFrameMetaData cloneGifFrameMetaData = clone.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData cloneGifFrameMetaData = clone.GetOrAddFormatMetaData(GifFormat.Instance); Assert.Equal(frameDelay, cloneGifFrameMetaData.FrameDelay); Assert.Equal(colorTableLength, cloneGifFrameMetaData.ColorTableLength); From 99976764c082932795082c477d8b7ab1ff69718a Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Mon, 10 Sep 2018 10:14:55 +0200 Subject: [PATCH 050/185] Reverted from DebugGuard back to Clamp. Added missing AgressiveInlinings. --- .../DefaultPixelBlenders.Generated.cs | 432 +++++++++++++----- .../DefaultPixelBlenders.Generated.tt | 4 +- .../PorterDuffFunctions.Generated.cs | 396 ++++------------ .../PorterDuffFunctions.Generated.tt | 46 +- .../PixelBlenders/PorterDuffFunctions.cs | 31 +- 5 files changed, 444 insertions(+), 465 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 409938f6e3..aa261c1f03 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -44,7 +44,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrc(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -77,7 +79,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrc(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplySrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -110,7 +114,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrc(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -143,7 +149,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrc(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -176,7 +184,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrc(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -209,7 +219,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrc(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -242,7 +254,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrc(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -275,7 +289,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrc(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlaySrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -308,7 +324,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrc(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -341,7 +359,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrcAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -374,7 +394,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrcAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -407,7 +429,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrcAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -440,7 +464,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrcAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -473,7 +499,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrcAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -506,7 +534,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrcAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -539,7 +569,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrcAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -572,7 +604,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrcAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -605,7 +639,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrcAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -638,7 +674,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrcOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -671,7 +709,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrcOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplySrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -704,7 +744,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrcOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -737,7 +779,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrcOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -770,7 +814,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrcOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -803,7 +849,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrcOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -836,7 +884,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrcOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -869,7 +919,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrcOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlaySrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -902,7 +954,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrcOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -935,7 +989,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrcIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -968,7 +1024,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrcIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplySrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1001,7 +1059,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrcIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1034,7 +1094,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrcIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1067,7 +1129,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrcIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1100,7 +1164,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrcIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1133,7 +1199,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrcIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1166,7 +1234,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrcIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlaySrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1199,7 +1269,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrcIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1232,7 +1304,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalSrcOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1265,7 +1339,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplySrcOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplySrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1298,7 +1374,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddSrcOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1331,7 +1409,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractSrcOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1364,7 +1444,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenSrcOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1397,7 +1479,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenSrcOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1430,7 +1514,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenSrcOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1463,7 +1549,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlaySrcOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlaySrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1496,7 +1584,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightSrcOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1529,7 +1619,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDest(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1562,7 +1654,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDest(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplyDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1595,7 +1689,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDest(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1628,7 +1724,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDest(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1661,7 +1759,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDest(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1694,7 +1794,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDest(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1727,7 +1829,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDest(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1760,7 +1864,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDest(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlayDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1793,7 +1899,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDest(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1826,7 +1934,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDestAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1859,7 +1969,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDestAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1892,7 +2004,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDestAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1925,7 +2039,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDestAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1958,7 +2074,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDestAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -1991,7 +2109,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDestAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2024,7 +2144,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDestAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2057,7 +2179,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDestAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlayDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2090,7 +2214,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDestAtop(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2123,7 +2249,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDestOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2156,7 +2284,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDestOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplyDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2189,7 +2319,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDestOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2222,7 +2354,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDestOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2255,7 +2389,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDestOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2288,7 +2424,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDestOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2321,7 +2459,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDestOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2354,7 +2494,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDestOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlayDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2387,7 +2529,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDestOver(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2420,7 +2564,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDestIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2453,7 +2599,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDestIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplyDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2486,7 +2634,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDestIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2519,7 +2669,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDestIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2552,7 +2704,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDestIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2585,7 +2739,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDestIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2618,7 +2774,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDestIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2651,7 +2809,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDestIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlayDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2684,7 +2844,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDestIn(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2717,7 +2879,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalDestOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2750,7 +2914,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyDestOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplyDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2783,7 +2949,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddDestOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2816,7 +2984,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractDestOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2849,7 +3019,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenDestOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2882,7 +3054,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenDestOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2915,7 +3089,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenDestOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2948,7 +3124,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayDestOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlayDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -2981,7 +3159,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightDestOut(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3014,7 +3194,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalClear(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3047,7 +3229,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyClear(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplyClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3080,7 +3264,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddClear(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3113,7 +3299,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractClear(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3146,7 +3334,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenClear(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3179,7 +3369,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenClear(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3212,7 +3404,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenClear(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3245,7 +3439,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayClear(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlayClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3278,7 +3474,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightClear(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3311,7 +3509,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.NormalXor(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.NormalXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3344,7 +3544,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.MultiplyXor(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.MultiplyXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3377,7 +3579,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.AddXor(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.AddXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3410,7 +3614,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.SubtractXor(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.SubtractXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3443,7 +3649,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.ScreenXor(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.ScreenXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3476,7 +3684,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.DarkenXor(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.DarkenXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3509,7 +3719,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.LightenXor(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.LightenXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3542,7 +3754,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.OverlayXor(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.OverlayXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// @@ -3575,7 +3789,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.HardLightXor(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.HardLightXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index a61041c86c..2152862dc5 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -80,7 +80,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - return PorterDuffFunctions.<#=blender_composer#>(background, source, amount.Clamp(0,1)); + TPixel dest = default; + dest.PackFromVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + return dest; } /// diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index 841f6ea856..73f6867e28 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -19,9 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrc(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -29,9 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, Normal(backdrop, source)); } @@ -39,9 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, Normal(backdrop, source)); } @@ -49,9 +43,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, Normal(backdrop, source)); } @@ -59,9 +51,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -75,9 +65,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, Normal(source, backdrop)); } @@ -85,9 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, Normal(source, backdrop)); } @@ -95,9 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, Normal(source, backdrop)); } @@ -105,9 +89,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -115,9 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalXor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -125,9 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalClear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } @@ -267,9 +245,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrc(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -277,9 +253,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, Multiply(backdrop, source)); } @@ -287,9 +261,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, Multiply(backdrop, source)); } @@ -297,9 +269,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, Multiply(backdrop, source)); } @@ -307,9 +277,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -323,9 +291,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, Multiply(source, backdrop)); } @@ -333,9 +299,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, Multiply(source, backdrop)); } @@ -343,9 +307,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, Multiply(source, backdrop)); } @@ -353,9 +315,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -363,9 +323,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyXor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -373,9 +331,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyClear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } @@ -515,9 +471,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrc(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -525,9 +479,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, Add(backdrop, source)); } @@ -535,9 +487,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, Add(backdrop, source)); } @@ -545,9 +495,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, Add(backdrop, source)); } @@ -555,9 +503,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -571,9 +517,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, Add(source, backdrop)); } @@ -581,9 +525,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, Add(source, backdrop)); } @@ -591,9 +533,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, Add(source, backdrop)); } @@ -601,9 +541,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -611,9 +549,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddXor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -621,9 +557,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddClear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } @@ -763,9 +697,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrc(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -773,9 +705,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, Subtract(backdrop, source)); } @@ -783,9 +713,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, Subtract(backdrop, source)); } @@ -793,9 +721,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, Subtract(backdrop, source)); } @@ -803,9 +729,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -819,9 +743,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, Subtract(source, backdrop)); } @@ -829,9 +751,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, Subtract(source, backdrop)); } @@ -839,9 +759,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, Subtract(source, backdrop)); } @@ -849,9 +767,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -859,9 +775,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractXor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -869,9 +783,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractClear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } @@ -1011,9 +923,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrc(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -1021,9 +931,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, Screen(backdrop, source)); } @@ -1031,9 +939,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, Screen(backdrop, source)); } @@ -1041,9 +947,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, Screen(backdrop, source)); } @@ -1051,9 +955,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -1067,9 +969,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, Screen(source, backdrop)); } @@ -1077,9 +977,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, Screen(source, backdrop)); } @@ -1087,9 +985,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, Screen(source, backdrop)); } @@ -1097,9 +993,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -1107,9 +1001,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenXor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -1117,9 +1009,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenClear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } @@ -1259,9 +1149,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrc(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -1269,9 +1157,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, Darken(backdrop, source)); } @@ -1279,9 +1165,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, Darken(backdrop, source)); } @@ -1289,9 +1173,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, Darken(backdrop, source)); } @@ -1299,9 +1181,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -1315,9 +1195,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, Darken(source, backdrop)); } @@ -1325,9 +1203,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, Darken(source, backdrop)); } @@ -1335,9 +1211,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, Darken(source, backdrop)); } @@ -1345,9 +1219,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -1355,9 +1227,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenXor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -1365,9 +1235,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenClear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } @@ -1507,9 +1375,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrc(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -1517,9 +1383,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, Lighten(backdrop, source)); } @@ -1527,9 +1391,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, Lighten(backdrop, source)); } @@ -1537,9 +1399,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, Lighten(backdrop, source)); } @@ -1547,9 +1407,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -1563,9 +1421,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, Lighten(source, backdrop)); } @@ -1573,9 +1429,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, Lighten(source, backdrop)); } @@ -1583,9 +1437,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, Lighten(source, backdrop)); } @@ -1593,9 +1445,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -1603,9 +1453,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenXor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -1613,9 +1461,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenClear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } @@ -1755,9 +1601,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrc(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -1765,9 +1609,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, Overlay(backdrop, source)); } @@ -1775,9 +1617,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, Overlay(backdrop, source)); } @@ -1785,9 +1625,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, Overlay(backdrop, source)); } @@ -1795,9 +1633,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -1811,9 +1647,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, Overlay(source, backdrop)); } @@ -1821,9 +1655,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, Overlay(source, backdrop)); } @@ -1831,9 +1663,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, Overlay(source, backdrop)); } @@ -1841,9 +1671,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -1851,9 +1679,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayXor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -1861,9 +1687,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayClear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } @@ -2003,9 +1827,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrc(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -2013,9 +1835,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, HardLight(backdrop, source)); } @@ -2023,9 +1843,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, HardLight(backdrop, source)); } @@ -2033,9 +1851,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, HardLight(backdrop, source)); } @@ -2043,9 +1859,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -2059,9 +1873,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, HardLight(source, backdrop)); } @@ -2069,9 +1881,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, HardLight(source, backdrop)); } @@ -2079,9 +1889,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, HardLight(source, backdrop)); } @@ -2089,9 +1897,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -2099,9 +1905,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightXor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -2109,9 +1913,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightClear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 7d5b8663df..e4a55abb88 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -27,9 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Src(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return source; } @@ -37,9 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(backdrop, source, <#=blender#>(backdrop, source)); } @@ -47,9 +43,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(backdrop, source, <#=blender#>(backdrop, source)); } @@ -57,9 +51,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(backdrop, source, <#=blender#>(backdrop, source)); } @@ -67,9 +59,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(backdrop, source); } @@ -83,9 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestAtop(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Atop(source, backdrop, <#=blender#>(source, backdrop)); } @@ -93,9 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestOver(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Over(source, backdrop, <#=blender#>(source, backdrop)); } @@ -103,9 +89,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestIn(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return In(source, backdrop, <#=blender#>(source, backdrop)); } @@ -113,9 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestOut(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Out(source, backdrop); } @@ -123,9 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Xor(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Xor(backdrop, source); } @@ -133,9 +113,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Clear(Vector4 backdrop, Vector4 source, float opacity) { - DebugGuard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - source.W *= opacity; + source.W *= opacity.Clamp(0,1); return Clear(backdrop, source); } @@ -186,7 +164,7 @@ string[] blenders = new []{ foreach(var blender in blenders) { - GeneratePixelBlenders(blender); + GeneratePixelBlenders(blender); foreach(var composer in composers) { diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs index e10c8fe918..9d0e9d04d3 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.cs @@ -8,7 +8,7 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { /// - /// Collection of Porter Duff alpha blending functions applying an the 'Over' composition model. + /// Collection of Porter Duff Color Blending and Alpha Composition Functions. /// /// /// These functions are designed to be a general solution for all color cases, @@ -148,31 +148,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return backdrop <= 0.5f ? (2 * backdrop * source) : 1 - ((2 * (1 - source)) * (1 - backdrop)); } - /// - /// General composition function for all modes, with a general solution for alpha channel - /// - /// Original Backdrop color - /// Original source color - /// Desired transformed color, without taking Alpha channel in account - /// The final color [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector4 SrcOverReference(Vector4 backdrop, Vector4 source, Vector4 xform) - { - // calculate weights - float xw = backdrop.W * source.W; - float bw = backdrop.W - xw; - float sw = source.W - xw; - - // calculate final alpha - float a = xw + bw + sw; - - // calculate final value - xform = ((xform * xw) + (backdrop * bw) + (source * sw)) / MathF.Max(a, Constants.Epsilon); - xform.W = a; - - return xform; - } - public static Vector4 Over(Vector4 dst, Vector4 src, Vector4 blend) { // calculate weights @@ -193,6 +169,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return color; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Atop(Vector4 dst, Vector4 src, Vector4 blend) { // calculate weights @@ -212,6 +189,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return color; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 In(Vector4 dst, Vector4 src, Vector4 blend) { float alpha = dst.W * src.W; @@ -223,6 +201,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return color; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Out(Vector4 dst, Vector4 src) { float alpha = (1 - dst.W) * src.W; @@ -234,6 +213,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return color; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 Xor(Vector4 dst, Vector4 src) { float srcW = 1 - dst.W; @@ -249,6 +229,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return color; } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector4 Clear(Vector4 backdrop, Vector4 source) { return Vector4.Zero; From c95ead7baf7c5b37c435aa1d6ab7dc6cd802044a Mon Sep 17 00:00:00 2001 From: Vicente Penades Date: Mon, 10 Sep 2018 13:05:05 +0200 Subject: [PATCH 051/185] reverted some changes from using DebugGuard replaced *Vector with *ScaledVector conversion methods --- .../Processors/Drawing/FillRegionProcessor.cs | 29 +-- .../Processors/Text/DrawTextProcessor.cs | 21 +- .../Processing/SolidBrush{TPixel}.cs | 15 +- .../DefaultPixelBlenders.Generated.cs | 216 +++++++++--------- .../DefaultPixelBlenders.Generated.tt | 2 +- .../PixelFormats/PixelBlender{TPixel}.cs | 12 +- 6 files changed, 128 insertions(+), 167 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs index d44251d073..514249a2d4 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillRegionProcessor.cs @@ -139,14 +139,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { for (float x = scanStart; x < startX + 1; x += subpixelFraction) { - scanline[startX] += subpixelFractionPoint; - scanlineDirty = true; - } - - if (scanline[startX] > 1) - { - scanline[startX] = 1; - } + scanline[startX] += subpixelFractionPoint; + scanlineDirty = true; + } } if (endX >= 0 && endX < scanline.Length) @@ -154,13 +149,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing for (float x = endX; x < scanEnd; x += subpixelFraction) { scanline[endX] += subpixelFractionPoint; - scanlineDirty = true; - } - - if (scanline[endX] > 1) - { - scanline[endX] = 1; - } + scanlineDirty = true; + } } int nextX = startX + 1; @@ -168,13 +158,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing nextX = Math.Max(nextX, 0); for (int x = nextX; x < endX; x++) { - scanline[x] += subpixelFraction; - scanlineDirty = true; - - if (scanline[x] > 1) - { - scanline[x] = 1; - } + scanline[x] += subpixelFraction; + scanlineDirty = true; } } } diff --git a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs index d7a46c1be9..1095de325f 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Text/DrawTextProcessor.cs @@ -386,12 +386,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text { scanline[startX] += subpixelFractionPoint; scanlineDirty = true; - } - - if (scanline[startX] > 1) - { - scanline[startX] = 1; - } + } } if (endX >= 0 && endX < scanline.Length) @@ -400,12 +395,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text { scanline[endX] += subpixelFractionPoint; scanlineDirty = true; - } - - if (scanline[endX] > 1) - { - scanline[endX] = 1; - } + } } int nextX = startX + 1; @@ -414,12 +404,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Text for (int x = nextX; x < endX; x++) { scanline[x] += subpixelFraction; - scanlineDirty = true; - - if (scanline[x] > 1) - { - scanline[x] = 1; - } + scanlineDirty = true; } } } diff --git a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs index 7e724572a9..6b69c33f07 100644 --- a/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs +++ b/src/ImageSharp.Drawing/Processing/SolidBrush{TPixel}.cs @@ -91,18 +91,9 @@ namespace SixLabors.ImageSharp.Processing { Span destinationRow = this.Target.GetPixelRowSpan(y).Slice(x, scanline.Length); - MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; - -#if DEBUG - for (int i = 0; i < scanline.Length; i++) - { - Guard.MustBeBetweenOrEqualTo(scanline[i], 0, 1, nameof(scanline)); - } -#endif - - float opacity = this.Options.BlendPercentage.Clamp(0, 1); + MemoryAllocator memoryAllocator = this.Target.MemoryAllocator; - if (opacity == 1f) + if (this.Options.BlendPercentage == 1f) { this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), scanline); } @@ -114,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing for (int i = 0; i < scanline.Length; i++) { - amountSpan[i] = scanline[i] * opacity; + amountSpan[i] = scanline[i] * this.Options.BlendPercentage; } this.Blender.Blend(memoryAllocator, destinationRow, destinationRow, this.Colors.GetSpan(), amountSpan); diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index aa261c1f03..cd3b5d4273 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -45,7 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplySrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -115,7 +115,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -185,7 +185,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -220,7 +220,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -255,7 +255,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -290,7 +290,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlaySrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -325,7 +325,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightSrc(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -360,7 +360,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -395,7 +395,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -430,7 +430,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -465,7 +465,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -500,7 +500,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -535,7 +535,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -570,7 +570,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -605,7 +605,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -640,7 +640,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -675,7 +675,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -710,7 +710,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplySrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -745,7 +745,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -780,7 +780,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -815,7 +815,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -850,7 +850,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -885,7 +885,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -920,7 +920,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlaySrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -955,7 +955,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightSrcOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -990,7 +990,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1025,7 +1025,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplySrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1060,7 +1060,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1095,7 +1095,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1130,7 +1130,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1165,7 +1165,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1200,7 +1200,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1235,7 +1235,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlaySrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1270,7 +1270,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightSrcIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1305,7 +1305,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1340,7 +1340,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplySrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1375,7 +1375,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1410,7 +1410,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1445,7 +1445,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1480,7 +1480,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1515,7 +1515,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1550,7 +1550,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlaySrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1585,7 +1585,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightSrcOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1620,7 +1620,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1655,7 +1655,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplyDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1690,7 +1690,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1725,7 +1725,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1760,7 +1760,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1795,7 +1795,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1830,7 +1830,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1865,7 +1865,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlayDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1900,7 +1900,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightDest(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1935,7 +1935,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -1970,7 +1970,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2005,7 +2005,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2040,7 +2040,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2075,7 +2075,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2110,7 +2110,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2145,7 +2145,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2180,7 +2180,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlayDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2215,7 +2215,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightDestAtop(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2250,7 +2250,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2285,7 +2285,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplyDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2320,7 +2320,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2355,7 +2355,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2390,7 +2390,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2425,7 +2425,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2460,7 +2460,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2495,7 +2495,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlayDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2530,7 +2530,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightDestOver(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2565,7 +2565,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2600,7 +2600,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplyDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2635,7 +2635,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2670,7 +2670,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2705,7 +2705,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2740,7 +2740,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2775,7 +2775,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2810,7 +2810,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlayDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2845,7 +2845,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightDestIn(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2880,7 +2880,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2915,7 +2915,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplyDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2950,7 +2950,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -2985,7 +2985,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3020,7 +3020,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3055,7 +3055,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3090,7 +3090,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3125,7 +3125,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlayDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3160,7 +3160,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightDestOut(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3195,7 +3195,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3230,7 +3230,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplyClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3265,7 +3265,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3300,7 +3300,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3335,7 +3335,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3370,7 +3370,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3405,7 +3405,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3440,7 +3440,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlayClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3475,7 +3475,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightClear(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3510,7 +3510,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.NormalXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3545,7 +3545,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.MultiplyXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3580,7 +3580,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.AddXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3615,7 +3615,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.SubtractXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3650,7 +3650,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.ScreenXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3685,7 +3685,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.DarkenXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3720,7 +3720,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.LightenXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3755,7 +3755,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.OverlayXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } @@ -3790,7 +3790,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.HardLightXor(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index 2152862dc5..3a951cbc11 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToVector4(),source.ToVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index 8039922f21..fa17c7ca63 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -93,12 +93,12 @@ namespace SixLabors.ImageSharp.PixelFormats Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4(source, sourceSpan, destination.Length); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); } } @@ -127,12 +127,12 @@ namespace SixLabors.ImageSharp.PixelFormats Span backgroundSpan = buffer.Slice(destination.Length, destination.Length); Span sourceSpan = buffer.Slice(destination.Length * 2, destination.Length); - PixelOperations.Instance.ToVector4(background, backgroundSpan, destination.Length); - PixelOperations.Instance.ToVector4(source, sourceSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4(background, backgroundSpan, destination.Length); + PixelOperations.Instance.ToScaledVector4(source, sourceSpan, destination.Length); this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount.Clamp(0, 1)); - PixelOperations.Instance.PackFromVector4(destinationSpan, destination, destination.Length); + PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); } } } From 9c3cd95084cbe84b95668f5a5cbdec85407d624e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 10 Sep 2018 13:25:08 +0100 Subject: [PATCH 052/185] Remove duplicate clamping and normalize vector scaling. --- .../Processing/DrawImageExtensions.cs | 182 +- .../DefaultPixelBlenders.Generated.cs | 7732 +++++++++-------- .../DefaultPixelBlenders.Generated.tt | 5 +- .../PorterDuffFunctions.Generated.cs | 522 +- .../PorterDuffFunctions.Generated.tt | 25 +- .../PixelFormats/PixelBlender{TPixel}.cs | 2 +- 6 files changed, 4343 insertions(+), 4125 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs b/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs index d236ec35c6..a8ee4d90bc 100644 --- a/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs +++ b/src/ImageSharp.Drawing/Processing/DrawImageExtensions.cs @@ -1,137 +1,137 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Drawing; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing -{ - /// - /// Adds extensions that allow the drawing of images to the type. - /// - public static class DrawImageExtensions - { - /// - /// Draws the given image together with the current one by blending their pixels. - /// +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing.Processors.Drawing; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing +{ + /// + /// Adds extensions that allow the drawing of images to the type. + /// + public static class DrawImageExtensions + { + /// + /// Draws the given image together with the current one by blending their pixels. + /// /// The pixel format of the destination image. - /// The pixel format of the source image. - /// The image this method extends. - /// The image to blend with the currently processing image. - /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, float opacity) + /// The pixel format of the source image. + /// The image this method extends. + /// The image to blend with the currently processing image. + /// The opacity of the image to blend. Must be between 0 and 1. + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, float opacity) where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity)); - - /// - /// Draws the given image together with the current one by blending their pixels. - /// + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity)); + + /// + /// Draws the given image together with the current one by blending their pixels. + /// /// The pixel format of the destination image. - /// The pixel format of the source image. - /// The image this method extends. - /// The image to blend with the currently processing image. - /// The blending mode. - /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, float opacity) + /// The pixel format of the source image. + /// The image this method extends. + /// The image to blend with the currently processing image. + /// The blending mode. + /// The opacity of the image to blend. Must be between 0 and 1. + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, float opacity) where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel + where TPixelSrc : struct, IPixel => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity)); - /// - /// 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. + /// /// The pixel format of the destination image. - /// The pixel format of the source image. - /// The image this method extends. - /// The image to blend with the currently processing image. + /// The pixel format of the source image. + /// The image this method extends. + /// The image to blend with the currently processing image. /// The color blending mode. - /// The alpha composition mode. - /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) + /// The alpha composition mode. + /// The opacity of the image to blend. Must be between 0 and 1. + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel + where TPixelSrc : struct, IPixel => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, colorBlending, alphaComposition, opacity)); - /// - /// 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. + /// /// The pixel format of the destination image. - /// The pixel format of the source image. + /// The pixel format of the source image. /// The image this method extends. - /// The image to blend with the currently processing image. + /// The image to blend with the currently processing image. /// The options, including the blending type and blending amount. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, GraphicsOptions options) + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, GraphicsOptions options) where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel + where TPixelSrc : struct, IPixel => source.ApplyProcessor(new DrawImageProcessor(image, Point.Empty, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage)); - /// - /// 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. /// /// The pixel format of the destination image. - /// The pixel format of the source image. - /// The image this method extends. + /// The pixel format of the source image. + /// The image this method extends. /// The image to blend with the currently processing image. - /// The location to draw the blended image. + /// The location to draw the blended image. /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, float opacity) + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, float opacity) where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel + where TPixelSrc : struct, IPixel => source.ApplyProcessor(new DrawImageProcessor(image, location, GraphicsOptions.Default.ColorBlendingMode, GraphicsOptions.Default.AlphaCompositionMode, opacity)); - /// - /// 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. /// /// The pixel format of the destination image. - /// The pixel format of the source image. - /// The image this method extends. + /// The pixel format of the source image. + /// The image this method extends. /// The image to blend with the currently processing image. - /// The location to draw the blended image. - /// The color blending to apply. + /// The location to draw the blended image. + /// The color blending to apply. /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, float opacity) + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, float opacity) where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel + where TPixelSrc : struct, IPixel => source.ApplyProcessor(new DrawImageProcessor(image, location, colorBlending, GraphicsOptions.Default.AlphaCompositionMode, opacity)); - /// - /// 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. /// /// The pixel format of the destination image. - /// The pixel format of the source image. - /// The image this method extends. + /// The pixel format of the source image. + /// The image this method extends. /// The image to blend with the currently processing image. - /// The location to draw the blended image. + /// The location to draw the blended image. /// The color blending to apply. - /// The alpha composition mode. + /// The alpha composition mode. /// The opacity of the image to blend. Must be between 0 and 1. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, PixelColorBlendingMode colorBlending, PixelAlphaCompositionMode alphaComposition, float opacity) where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel + where TPixelSrc : struct, IPixel => source.ApplyProcessor(new DrawImageProcessor(image, location, colorBlending, alphaComposition, opacity)); - /// - /// 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. /// /// The pixel format of the destination image. - /// The pixel format of the source image. + /// The pixel format of the source image. /// The image this method extends. /// The image to blend with the currently processing image. /// The location to draw the blended image. - /// The options containing the blend mode and opacity. - /// The . - public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, GraphicsOptions options) + /// The options containing the blend mode and opacity. + /// The . + public static IImageProcessingContext DrawImage(this IImageProcessingContext source, Image image, Point location, GraphicsOptions options) where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel - => source.ApplyProcessor(new DrawImageProcessor(image, location, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage)); - } + where TPixelSrc : struct, IPixel + => source.ApplyProcessor(new DrawImageProcessor(image, location, options.ColorBlendingMode, options.AlphaCompositionMode, options.BlendPercentage)); + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index cd3b5d4273..19d1c5dad1 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -1,3818 +1,3926 @@ - - - - - - - -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -// + + + + + + + +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +// using System; using System.Numerics; using System.Buffers; using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; - -namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders -{ - /// - /// Collection of Porter Duff alpha blending functions applying different composition models. - /// - /// - /// 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 - /// and source, and there's no need to alpha-premultiply neither the backdrop - /// nor the source. - /// Note there are faster functions for when the backdrop color is known - /// to be opaque - /// - internal static class DefaultPixelBlenders - where TPixel : struct, IPixel - { - - - internal class NormalSrc : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalSrc Instance { get; } = new NormalSrc(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplySrc : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplySrc Instance { get; } = new MultiplySrc(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount[i]); - } - } - } - - - internal class AddSrc : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddSrc Instance { get; } = new AddSrc(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractSrc : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractSrc Instance { get; } = new SubtractSrc(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenSrc : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenSrc Instance { get; } = new ScreenSrc(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenSrc : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenSrc Instance { get; } = new DarkenSrc(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenSrc : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenSrc Instance { get; } = new LightenSrc(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlaySrc : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlaySrc Instance { get; } = new OverlaySrc(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightSrc : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightSrc Instance { get; } = new HardLightSrc(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalSrcAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalSrcAtop Instance { get; } = new NormalSrcAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplySrcAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplySrcAtop Instance { get; } = new MultiplySrcAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class AddSrcAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddSrcAtop Instance { get; } = new AddSrcAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractSrcAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractSrcAtop Instance { get; } = new SubtractSrcAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenSrcAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenSrcAtop Instance { get; } = new ScreenSrcAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenSrcAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenSrcAtop Instance { get; } = new DarkenSrcAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenSrcAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenSrcAtop Instance { get; } = new LightenSrcAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlaySrcAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlaySrcAtop Instance { get; } = new OverlaySrcAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightSrcAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightSrcAtop Instance { get; } = new HardLightSrcAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalSrcOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalSrcOver Instance { get; } = new NormalSrcOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplySrcOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplySrcOver Instance { get; } = new MultiplySrcOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount[i]); - } - } - } - - - internal class AddSrcOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddSrcOver Instance { get; } = new AddSrcOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractSrcOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractSrcOver Instance { get; } = new SubtractSrcOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenSrcOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenSrcOver Instance { get; } = new ScreenSrcOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenSrcOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenSrcOver Instance { get; } = new DarkenSrcOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenSrcOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenSrcOver Instance { get; } = new LightenSrcOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlaySrcOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlaySrcOver Instance { get; } = new OverlaySrcOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightSrcOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightSrcOver Instance { get; } = new HardLightSrcOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalSrcIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalSrcIn Instance { get; } = new NormalSrcIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplySrcIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplySrcIn Instance { get; } = new MultiplySrcIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount[i]); - } - } - } - - - internal class AddSrcIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddSrcIn Instance { get; } = new AddSrcIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractSrcIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractSrcIn Instance { get; } = new SubtractSrcIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenSrcIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenSrcIn Instance { get; } = new ScreenSrcIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenSrcIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenSrcIn Instance { get; } = new DarkenSrcIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenSrcIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenSrcIn Instance { get; } = new LightenSrcIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlaySrcIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlaySrcIn Instance { get; } = new OverlaySrcIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightSrcIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightSrcIn Instance { get; } = new HardLightSrcIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalSrcOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalSrcOut Instance { get; } = new NormalSrcOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplySrcOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplySrcOut Instance { get; } = new MultiplySrcOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount[i]); - } - } - } - - - internal class AddSrcOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddSrcOut Instance { get; } = new AddSrcOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractSrcOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractSrcOut Instance { get; } = new SubtractSrcOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenSrcOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenSrcOut Instance { get; } = new ScreenSrcOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenSrcOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenSrcOut Instance { get; } = new DarkenSrcOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenSrcOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenSrcOut Instance { get; } = new LightenSrcOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlaySrcOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlaySrcOut Instance { get; } = new OverlaySrcOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightSrcOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightSrcOut Instance { get; } = new HardLightSrcOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalDest : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalDest Instance { get; } = new NormalDest(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplyDest : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplyDest Instance { get; } = new MultiplyDest(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount[i]); - } - } - } - - - internal class AddDest : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddDest Instance { get; } = new AddDest(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractDest : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractDest Instance { get; } = new SubtractDest(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenDest : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenDest Instance { get; } = new ScreenDest(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenDest : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenDest Instance { get; } = new DarkenDest(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenDest : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenDest Instance { get; } = new LightenDest(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlayDest : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlayDest Instance { get; } = new OverlayDest(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightDest : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightDest Instance { get; } = new HardLightDest(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalDestAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalDestAtop Instance { get; } = new NormalDestAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplyDestAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplyDestAtop Instance { get; } = new MultiplyDestAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class AddDestAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddDestAtop Instance { get; } = new AddDestAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractDestAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractDestAtop Instance { get; } = new SubtractDestAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenDestAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenDestAtop Instance { get; } = new ScreenDestAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenDestAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenDestAtop Instance { get; } = new DarkenDestAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenDestAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenDestAtop Instance { get; } = new LightenDestAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlayDestAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlayDestAtop Instance { get; } = new OverlayDestAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightDestAtop : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightDestAtop Instance { get; } = new HardLightDestAtop(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalDestOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalDestOver Instance { get; } = new NormalDestOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplyDestOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplyDestOver Instance { get; } = new MultiplyDestOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount[i]); - } - } - } - - - internal class AddDestOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddDestOver Instance { get; } = new AddDestOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractDestOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractDestOver Instance { get; } = new SubtractDestOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenDestOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenDestOver Instance { get; } = new ScreenDestOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenDestOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenDestOver Instance { get; } = new DarkenDestOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenDestOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenDestOver Instance { get; } = new LightenDestOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlayDestOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlayDestOver Instance { get; } = new OverlayDestOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightDestOver : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightDestOver Instance { get; } = new HardLightDestOver(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalDestIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalDestIn Instance { get; } = new NormalDestIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplyDestIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplyDestIn Instance { get; } = new MultiplyDestIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount[i]); - } - } - } - - - internal class AddDestIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddDestIn Instance { get; } = new AddDestIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractDestIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractDestIn Instance { get; } = new SubtractDestIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenDestIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenDestIn Instance { get; } = new ScreenDestIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenDestIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenDestIn Instance { get; } = new DarkenDestIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenDestIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenDestIn Instance { get; } = new LightenDestIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlayDestIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlayDestIn Instance { get; } = new OverlayDestIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightDestIn : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightDestIn Instance { get; } = new HardLightDestIn(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalDestOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalDestOut Instance { get; } = new NormalDestOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplyDestOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplyDestOut Instance { get; } = new MultiplyDestOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount[i]); - } - } - } - - - internal class AddDestOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddDestOut Instance { get; } = new AddDestOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractDestOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractDestOut Instance { get; } = new SubtractDestOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenDestOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenDestOut Instance { get; } = new ScreenDestOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenDestOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenDestOut Instance { get; } = new DarkenDestOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenDestOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenDestOut Instance { get; } = new LightenDestOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlayDestOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlayDestOut Instance { get; } = new OverlayDestOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightDestOut : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightDestOut Instance { get; } = new HardLightDestOut(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalClear : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalClear Instance { get; } = new NormalClear(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplyClear : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplyClear Instance { get; } = new MultiplyClear(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount[i]); - } - } - } - - - internal class AddClear : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddClear Instance { get; } = new AddClear(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractClear : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractClear Instance { get; } = new SubtractClear(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenClear : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenClear Instance { get; } = new ScreenClear(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenClear : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenClear Instance { get; } = new DarkenClear(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenClear : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenClear Instance { get; } = new LightenClear(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlayClear : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlayClear Instance { get; } = new OverlayClear(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightClear : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightClear Instance { get; } = new HardLightClear(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount[i]); - } - } - } - - - internal class NormalXor : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static NormalXor Instance { get; } = new NormalXor(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount[i]); - } - } - } - - - internal class MultiplyXor : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static MultiplyXor Instance { get; } = new MultiplyXor(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount[i]); - } - } - } - - - internal class AddXor : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static AddXor Instance { get; } = new AddXor(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount[i]); - } - } - } - - - internal class SubtractXor : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static SubtractXor Instance { get; } = new SubtractXor(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount[i]); - } - } - } - - - internal class ScreenXor : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static ScreenXor Instance { get; } = new ScreenXor(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount[i]); - } - } - } - - - internal class DarkenXor : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static DarkenXor Instance { get; } = new DarkenXor(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount[i]); - } - } - } - - - internal class LightenXor : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static LightenXor Instance { get; } = new LightenXor(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount[i]); - } - } - } - - - internal class OverlayXor : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static OverlayXor Instance { get; } = new OverlayXor(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount[i]); - } - } - } - - - internal class HardLightXor : PixelBlender - { - /// - /// Gets the static instance of this blender. - /// - public static HardLightXor Instance { get; } = new HardLightXor(); - - /// - public override TPixel Blend(TPixel background, TPixel source, float amount) - { - TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); - return dest; - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount); - } - } - - /// - protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) - { - for (int i = 0; i < destination.Length; i++) - { - destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount[i]); - } - } - } - - - } +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders +{ + /// + /// Collection of Porter Duff alpha blending functions applying different composition models. + /// + /// + /// 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 + /// and source, and there's no need to alpha-premultiply neither the backdrop + /// nor the source. + /// Note there are faster functions for when the backdrop color is known + /// to be opaque + /// + internal static class DefaultPixelBlenders + where TPixel : struct, IPixel + { + + + internal class NormalSrc : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalSrc Instance { get; } = new NormalSrc(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrc(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplySrc : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplySrc Instance { get; } = new MultiplySrc(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrc(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddSrc : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddSrc Instance { get; } = new AddSrc(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrc(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractSrc : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractSrc Instance { get; } = new SubtractSrc(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrc(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenSrc : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenSrc Instance { get; } = new ScreenSrc(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrc(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenSrc : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenSrc Instance { get; } = new DarkenSrc(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrc(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenSrc : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenSrc Instance { get; } = new LightenSrc(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrc(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlaySrc : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlaySrc Instance { get; } = new OverlaySrc(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrc(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightSrc : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightSrc Instance { get; } = new HardLightSrc(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrc(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalSrcAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalSrcAtop Instance { get; } = new NormalSrcAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplySrcAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplySrcAtop Instance { get; } = new MultiplySrcAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddSrcAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddSrcAtop Instance { get; } = new AddSrcAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractSrcAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractSrcAtop Instance { get; } = new SubtractSrcAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenSrcAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenSrcAtop Instance { get; } = new ScreenSrcAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenSrcAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenSrcAtop Instance { get; } = new DarkenSrcAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenSrcAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenSrcAtop Instance { get; } = new LightenSrcAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlaySrcAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlaySrcAtop Instance { get; } = new OverlaySrcAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightSrcAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightSrcAtop Instance { get; } = new HardLightSrcAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalSrcOver Instance { get; } = new NormalSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplySrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplySrcOver Instance { get; } = new MultiplySrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddSrcOver Instance { get; } = new AddSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractSrcOver Instance { get; } = new SubtractSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenSrcOver Instance { get; } = new ScreenSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenSrcOver Instance { get; } = new DarkenSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenSrcOver Instance { get; } = new LightenSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlaySrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlaySrcOver Instance { get; } = new OverlaySrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightSrcOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightSrcOver Instance { get; } = new HardLightSrcOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalSrcIn Instance { get; } = new NormalSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplySrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplySrcIn Instance { get; } = new MultiplySrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddSrcIn Instance { get; } = new AddSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractSrcIn Instance { get; } = new SubtractSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenSrcIn Instance { get; } = new ScreenSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenSrcIn Instance { get; } = new DarkenSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenSrcIn Instance { get; } = new LightenSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlaySrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlaySrcIn Instance { get; } = new OverlaySrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightSrcIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightSrcIn Instance { get; } = new HardLightSrcIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalSrcOut Instance { get; } = new NormalSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalSrcOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplySrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplySrcOut Instance { get; } = new MultiplySrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplySrcOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddSrcOut Instance { get; } = new AddSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddSrcOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractSrcOut Instance { get; } = new SubtractSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractSrcOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenSrcOut Instance { get; } = new ScreenSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenSrcOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenSrcOut Instance { get; } = new DarkenSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenSrcOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenSrcOut Instance { get; } = new LightenSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenSrcOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlaySrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlaySrcOut Instance { get; } = new OverlaySrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlaySrcOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightSrcOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightSrcOut Instance { get; } = new HardLightSrcOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightSrcOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDest Instance { get; } = new NormalDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDest(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplyDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDest Instance { get; } = new MultiplyDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDest(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDest Instance { get; } = new AddDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDest(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDest Instance { get; } = new SubtractDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDest(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDest Instance { get; } = new ScreenDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDest(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDest Instance { get; } = new DarkenDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDest(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDest Instance { get; } = new LightenDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDest(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlayDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDest Instance { get; } = new OverlayDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDest(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightDest : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDest Instance { get; } = new HardLightDest(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDest(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDestAtop Instance { get; } = new NormalDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplyDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDestAtop Instance { get; } = new MultiplyDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDestAtop Instance { get; } = new AddDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDestAtop Instance { get; } = new SubtractDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDestAtop Instance { get; } = new ScreenDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDestAtop Instance { get; } = new DarkenDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDestAtop Instance { get; } = new LightenDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlayDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDestAtop Instance { get; } = new OverlayDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightDestAtop : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDestAtop Instance { get; } = new HardLightDestAtop(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestAtop(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDestOver Instance { get; } = new NormalDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplyDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDestOver Instance { get; } = new MultiplyDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDestOver Instance { get; } = new AddDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDestOver Instance { get; } = new SubtractDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDestOver Instance { get; } = new ScreenDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDestOver Instance { get; } = new DarkenDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDestOver Instance { get; } = new LightenDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlayDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDestOver Instance { get; } = new OverlayDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightDestOver : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDestOver Instance { get; } = new HardLightDestOver(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestOver(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDestIn Instance { get; } = new NormalDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplyDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDestIn Instance { get; } = new MultiplyDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDestIn Instance { get; } = new AddDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDestIn Instance { get; } = new SubtractDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDestIn Instance { get; } = new ScreenDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDestIn Instance { get; } = new DarkenDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDestIn Instance { get; } = new LightenDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlayDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDestIn Instance { get; } = new OverlayDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightDestIn : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDestIn Instance { get; } = new HardLightDestIn(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestIn(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalDestOut Instance { get; } = new NormalDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalDestOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplyDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyDestOut Instance { get; } = new MultiplyDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyDestOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddDestOut Instance { get; } = new AddDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddDestOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractDestOut Instance { get; } = new SubtractDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractDestOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenDestOut Instance { get; } = new ScreenDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenDestOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenDestOut Instance { get; } = new DarkenDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenDestOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenDestOut Instance { get; } = new LightenDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenDestOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlayDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayDestOut Instance { get; } = new OverlayDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayDestOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightDestOut : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightDestOut Instance { get; } = new HardLightDestOut(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightDestOut(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalClear Instance { get; } = new NormalClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalClear(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplyClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyClear Instance { get; } = new MultiplyClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyClear(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddClear Instance { get; } = new AddClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddClear(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractClear Instance { get; } = new SubtractClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractClear(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenClear Instance { get; } = new ScreenClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenClear(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenClear Instance { get; } = new DarkenClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenClear(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenClear Instance { get; } = new LightenClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenClear(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlayClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayClear Instance { get; } = new OverlayClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayClear(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightClear : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightClear Instance { get; } = new HardLightClear(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightClear(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class NormalXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static NormalXor Instance { get; } = new NormalXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.NormalXor(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class MultiplyXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static MultiplyXor Instance { get; } = new MultiplyXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.MultiplyXor(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class AddXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static AddXor Instance { get; } = new AddXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.AddXor(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class SubtractXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static SubtractXor Instance { get; } = new SubtractXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.SubtractXor(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class ScreenXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static ScreenXor Instance { get; } = new ScreenXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.ScreenXor(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class DarkenXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static DarkenXor Instance { get; } = new DarkenXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.DarkenXor(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class LightenXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static LightenXor Instance { get; } = new LightenXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.LightenXor(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class OverlayXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static OverlayXor Instance { get; } = new OverlayXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.OverlayXor(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + internal class HardLightXor : PixelBlender + { + /// + /// Gets the static instance of this blender. + /// + public static HardLightXor Instance { get; } = new HardLightXor(); + + /// + public override TPixel Blend(TPixel background, TPixel source, float amount) + { + TPixel dest = default; + dest.PackFromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); + return dest; + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) + { + amount = amount.Clamp(0, 1); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount); + } + } + + /// + protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, ReadOnlySpan amount) + { + for (int i = 0; i < destination.Length; i++) + { + destination[i] = PorterDuffFunctions.HardLightXor(background[i], source[i], amount[i].Clamp(0, 1)); + } + } + } + + + } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index 3a951cbc11..f776da7a02 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -81,13 +81,14 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public override TPixel Blend(TPixel background, TPixel source, float amount) { TPixel dest = default; - dest.PackFromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(),source.ToScaledVector4(),amount.Clamp(0,1))); + dest.PackFromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), amount.Clamp(0, 1))); return dest; } /// protected override void BlendFunction(Span destination, ReadOnlySpan background, ReadOnlySpan source, float amount) { + amount = amount.Clamp(0, 1); for (int i = 0; i < destination.Length; i++) { destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount); @@ -99,7 +100,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders { for (int i = 0; i < destination.Length; i++) { - destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount[i]); + destination[i] = PorterDuffFunctions.<#=blender_composer#>(background[i], source[i], amount[i].Clamp(0, 1)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index 73f6867e28..5ebda01994 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrc(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, Normal(backdrop, source)); } @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, Normal(backdrop, source)); } @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, Normal(backdrop, source)); } @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, Normal(source, backdrop)); } @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, Normal(source, backdrop)); } @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, Normal(source, backdrop)); } @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalXor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 NormalClear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -115,8 +115,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalSrc(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -126,8 +127,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalSrcAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -137,8 +139,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalSrcOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -148,8 +151,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalSrcIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -159,8 +163,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalSrcOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -170,8 +175,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalDest(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -181,8 +187,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalDestAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -192,8 +199,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalDestOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -203,8 +211,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalDestIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -214,8 +223,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalDestOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -225,8 +235,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalClear(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -236,8 +247,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel NormalXor(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(NormalXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -245,7 +257,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrc(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -253,7 +265,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, Multiply(backdrop, source)); } @@ -261,7 +273,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, Multiply(backdrop, source)); } @@ -269,7 +281,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, Multiply(backdrop, source)); } @@ -277,7 +289,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplySrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -291,7 +303,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, Multiply(source, backdrop)); } @@ -299,7 +311,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, Multiply(source, backdrop)); } @@ -307,7 +319,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, Multiply(source, backdrop)); } @@ -315,7 +327,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -323,7 +335,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyXor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -331,7 +343,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 MultiplyClear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -341,8 +353,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplySrc(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplySrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -352,8 +365,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplySrcAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplySrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -363,8 +377,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplySrcOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplySrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -374,8 +389,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplySrcIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplySrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -385,8 +401,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplySrcOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplySrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -396,8 +413,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplyDest(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplyDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -407,8 +425,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplyDestAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplyDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -418,8 +437,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplyDestOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplyDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -429,8 +449,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplyDestIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplyDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -440,8 +461,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplyDestOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplyDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -451,8 +473,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplyClear(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplyClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -462,8 +485,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel MultiplyXor(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(MultiplyXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -471,7 +495,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrc(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -479,7 +503,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, Add(backdrop, source)); } @@ -487,7 +511,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, Add(backdrop, source)); } @@ -495,7 +519,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, Add(backdrop, source)); } @@ -503,7 +527,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -517,7 +541,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, Add(source, backdrop)); } @@ -525,7 +549,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, Add(source, backdrop)); } @@ -533,7 +557,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, Add(source, backdrop)); } @@ -541,7 +565,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -549,7 +573,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddXor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -557,7 +581,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 AddClear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -567,8 +591,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddSrc(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -578,8 +603,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddSrcAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -589,8 +615,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddSrcOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -600,8 +627,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddSrcIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -611,8 +639,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddSrcOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -622,8 +651,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddDest(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -633,8 +663,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddDestAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -644,8 +675,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddDestOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -655,8 +687,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddDestIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -666,8 +699,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddDestOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -677,8 +711,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddClear(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -688,8 +723,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel AddXor(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(AddXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -697,7 +733,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrc(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -705,7 +741,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, Subtract(backdrop, source)); } @@ -713,7 +749,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, Subtract(backdrop, source)); } @@ -721,7 +757,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, Subtract(backdrop, source)); } @@ -729,7 +765,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -743,7 +779,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, Subtract(source, backdrop)); } @@ -751,7 +787,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, Subtract(source, backdrop)); } @@ -759,7 +795,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, Subtract(source, backdrop)); } @@ -767,7 +803,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -775,7 +811,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractXor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -783,7 +819,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 SubtractClear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -793,8 +829,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractSrc(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -804,8 +841,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractSrcAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -815,8 +853,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractSrcOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -826,8 +865,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractSrcIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -837,8 +877,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractSrcOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -848,8 +889,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractDest(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -859,8 +901,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractDestAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -870,8 +913,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractDestOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -881,8 +925,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractDestIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -892,8 +937,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractDestOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -903,8 +949,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractClear(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -914,8 +961,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel SubtractXor(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(SubtractXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -923,7 +971,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrc(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -931,7 +979,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, Screen(backdrop, source)); } @@ -939,7 +987,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, Screen(backdrop, source)); } @@ -947,7 +995,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, Screen(backdrop, source)); } @@ -955,7 +1003,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -969,7 +1017,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, Screen(source, backdrop)); } @@ -977,7 +1025,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, Screen(source, backdrop)); } @@ -985,7 +1033,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, Screen(source, backdrop)); } @@ -993,7 +1041,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -1001,7 +1049,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenXor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -1009,7 +1057,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 ScreenClear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -1019,8 +1067,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenSrc(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1030,8 +1079,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenSrcAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1041,8 +1091,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenSrcOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1052,8 +1103,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenSrcIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1063,8 +1115,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenSrcOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1074,8 +1127,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenDest(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1085,8 +1139,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenDestAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1096,8 +1151,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenDestOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1107,8 +1163,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenDestIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1118,8 +1175,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenDestOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1129,8 +1187,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenClear(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1140,8 +1199,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel ScreenXor(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(ScreenXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1149,7 +1209,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrc(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -1157,7 +1217,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, Darken(backdrop, source)); } @@ -1165,7 +1225,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, Darken(backdrop, source)); } @@ -1173,7 +1233,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, Darken(backdrop, source)); } @@ -1181,7 +1241,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -1195,7 +1255,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, Darken(source, backdrop)); } @@ -1203,7 +1263,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, Darken(source, backdrop)); } @@ -1211,7 +1271,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, Darken(source, backdrop)); } @@ -1219,7 +1279,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -1227,7 +1287,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenXor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -1235,7 +1295,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 DarkenClear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -1245,8 +1305,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenSrc(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1256,8 +1317,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenSrcAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1267,8 +1329,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenSrcOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1278,8 +1341,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenSrcIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1289,8 +1353,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenSrcOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1300,8 +1365,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenDest(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1311,8 +1377,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenDestAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1322,8 +1389,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenDestOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1333,8 +1401,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenDestIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1344,8 +1413,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenDestOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1355,8 +1425,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenClear(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1366,8 +1437,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel DarkenXor(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(DarkenXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1375,7 +1447,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrc(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -1383,7 +1455,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, Lighten(backdrop, source)); } @@ -1391,7 +1463,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, Lighten(backdrop, source)); } @@ -1399,7 +1471,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, Lighten(backdrop, source)); } @@ -1407,7 +1479,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -1421,7 +1493,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, Lighten(source, backdrop)); } @@ -1429,7 +1501,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, Lighten(source, backdrop)); } @@ -1437,7 +1509,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, Lighten(source, backdrop)); } @@ -1445,7 +1517,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -1453,7 +1525,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenXor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -1461,7 +1533,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 LightenClear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -1471,8 +1543,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenSrc(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1482,8 +1555,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenSrcAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1493,8 +1567,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenSrcOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1504,8 +1579,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenSrcIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1515,8 +1591,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenSrcOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1526,8 +1603,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenDest(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1537,8 +1615,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenDestAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1548,8 +1627,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenDestOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1559,8 +1639,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenDestIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1570,8 +1651,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenDestOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1581,8 +1663,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenClear(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1592,8 +1675,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel LightenXor(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(LightenXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1601,7 +1685,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrc(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -1609,7 +1693,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, Overlay(backdrop, source)); } @@ -1617,7 +1701,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, Overlay(backdrop, source)); } @@ -1625,7 +1709,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, Overlay(backdrop, source)); } @@ -1633,7 +1717,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlaySrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -1647,7 +1731,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, Overlay(source, backdrop)); } @@ -1655,7 +1739,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, Overlay(source, backdrop)); } @@ -1663,7 +1747,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, Overlay(source, backdrop)); } @@ -1671,7 +1755,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -1679,7 +1763,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayXor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -1687,7 +1771,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 OverlayClear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -1697,8 +1781,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlaySrc(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlaySrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1708,8 +1793,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlaySrcAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlaySrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1719,8 +1805,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlaySrcOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlaySrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1730,8 +1817,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlaySrcIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlaySrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1741,8 +1829,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlaySrcOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlaySrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1752,8 +1841,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlayDest(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlayDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1763,8 +1853,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlayDestAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlayDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1774,8 +1865,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlayDestOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlayDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1785,8 +1877,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlayDestIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlayDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1796,8 +1889,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlayDestOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlayDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1807,8 +1901,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlayClear(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlayClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1818,8 +1913,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel OverlayXor(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(OverlayXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1827,7 +1923,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrc(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -1835,7 +1931,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, HardLight(backdrop, source)); } @@ -1843,7 +1939,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, HardLight(backdrop, source)); } @@ -1851,7 +1947,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, HardLight(backdrop, source)); } @@ -1859,7 +1955,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightSrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -1873,7 +1969,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, HardLight(source, backdrop)); } @@ -1881,7 +1977,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, HardLight(source, backdrop)); } @@ -1889,7 +1985,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, HardLight(source, backdrop)); } @@ -1897,7 +1993,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightDestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -1905,7 +2001,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightXor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -1913,7 +2009,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 HardLightClear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -1923,8 +2019,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightSrc(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightSrc(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1934,8 +2031,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightSrcAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightSrcAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1945,8 +2043,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightSrcOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightSrcOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1956,8 +2055,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightSrcIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightSrcIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1967,8 +2067,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightSrcOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightSrcOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1978,8 +2079,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightDest(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightDest(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -1989,8 +2091,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightDestAtop(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightDestAtop(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2000,8 +2103,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightDestOver(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightDestOver(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2011,8 +2115,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightDestIn(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightDestIn(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2022,8 +2127,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightDestOut(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightDestOut(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2033,8 +2139,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightClear(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightClear(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } @@ -2044,8 +2151,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel HardLightXor(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(HardLightXor(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index e4a55abb88..6960c2f1a7 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Src(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return source; } @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(backdrop, source, <#=blender#>(backdrop, source)); } @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(backdrop, source, <#=blender#>(backdrop, source)); } @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(backdrop, source, <#=blender#>(backdrop, source)); } @@ -59,7 +59,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>SrcOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(backdrop, source); } @@ -73,7 +73,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestAtop(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Atop(source, backdrop, <#=blender#>(source, backdrop)); } @@ -81,7 +81,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestOver(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Over(source, backdrop, <#=blender#>(source, backdrop)); } @@ -89,7 +89,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestIn(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return In(source, backdrop, <#=blender#>(source, backdrop)); } @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>DestOut(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Out(source, backdrop); } @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Xor(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Xor(backdrop, source); } @@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector4 <#=blender#>Clear(Vector4 backdrop, Vector4 source, float opacity) { - source.W *= opacity.Clamp(0,1); + source.W *= opacity; return Clear(backdrop, source); } @@ -126,8 +126,9 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders public static TPixel <#=blender#><#=composer#>(TPixel backdrop, TPixel source, float opacity) where TPixel : struct, IPixel { + opacity = opacity.Clamp(0, 1); TPixel dest = default; - dest.PackFromVector4(<#=blender#><#=composer#>(backdrop.ToVector4(),source.ToVector4(),opacity)); + dest.PackFromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); return dest; } diff --git a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs index fa17c7ca63..63a101656e 100644 --- a/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelBlender{TPixel}.cs @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.PixelFormats PixelOperations.Instance.ToScaledVector4(background, backgroundSpan, destination.Length); PixelOperations.Instance.ToScaledVector4(source, sourceSpan, destination.Length); - this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount.Clamp(0, 1)); + this.BlendFunction(destinationSpan, backgroundSpan, sourceSpan, amount); PixelOperations.Instance.PackFromScaledVector4(destinationSpan, destination, destination.Length); } From 7cf9cb578d4780e542c8f04f5b14039e0187803f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 10 Sep 2018 14:49:05 +0100 Subject: [PATCH 053/185] Use NoInlining to workaround Vector Jit bug. --- .../PorterDuffFunctions.Generated.cs | 217 +++++++++--------- .../PorterDuffFunctions.Generated.tt | 29 ++- 2 files changed, 126 insertions(+), 120 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index 5ebda01994..0a6ef60eca 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -3,6 +3,7 @@ // + using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -16,7 +17,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalSrc(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -24,7 +25,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -32,7 +33,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, Normal(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalSrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -40,7 +41,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, Normal(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalSrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -48,7 +49,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, Normal(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalSrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -56,13 +57,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalDest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalDestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -70,7 +71,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, Normal(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalDestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -78,7 +79,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, Normal(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalDestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -86,7 +87,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, Normal(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalDestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -94,7 +95,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalXor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -102,7 +103,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 NormalClear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -254,7 +255,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplySrc(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -262,7 +263,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -270,7 +271,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, Multiply(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplySrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -278,7 +279,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, Multiply(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplySrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -286,7 +287,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, Multiply(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplySrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -294,13 +295,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplyDest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplyDestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -308,7 +309,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, Multiply(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplyDestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -316,7 +317,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, Multiply(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplyDestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -324,7 +325,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, Multiply(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplyDestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -332,7 +333,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplyXor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -340,7 +341,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 MultiplyClear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -492,7 +493,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddSrc(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -500,7 +501,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -508,7 +509,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, Add(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddSrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -516,7 +517,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, Add(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddSrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -524,7 +525,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, Add(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddSrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -532,13 +533,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddDest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddDestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -546,7 +547,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, Add(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddDestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -554,7 +555,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, Add(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddDestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -562,7 +563,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, Add(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddDestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -570,7 +571,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddXor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -578,7 +579,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 AddClear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -730,7 +731,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractSrc(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -738,7 +739,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -746,7 +747,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, Subtract(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractSrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -754,7 +755,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, Subtract(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractSrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -762,7 +763,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, Subtract(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractSrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -770,13 +771,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractDest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractDestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -784,7 +785,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, Subtract(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractDestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -792,7 +793,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, Subtract(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractDestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -800,7 +801,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, Subtract(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractDestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -808,7 +809,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractXor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -816,7 +817,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 SubtractClear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -968,7 +969,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenSrc(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -976,7 +977,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -984,7 +985,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, Screen(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -992,7 +993,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, Screen(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1000,7 +1001,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, Screen(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1008,13 +1009,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenDest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1022,7 +1023,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, Screen(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenDestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1030,7 +1031,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, Screen(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenDestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1038,7 +1039,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, Screen(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenDestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1046,7 +1047,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenXor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1054,7 +1055,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 ScreenClear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1206,7 +1207,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenSrc(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1214,7 +1215,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1222,7 +1223,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, Darken(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1230,7 +1231,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, Darken(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1238,7 +1239,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, Darken(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1246,13 +1247,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenDest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1260,7 +1261,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, Darken(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenDestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1268,7 +1269,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, Darken(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenDestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1276,7 +1277,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, Darken(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenDestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1284,7 +1285,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenXor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1292,7 +1293,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 DarkenClear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1444,7 +1445,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenSrc(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1452,7 +1453,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1460,7 +1461,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, Lighten(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenSrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1468,7 +1469,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, Lighten(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenSrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1476,7 +1477,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, Lighten(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenSrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1484,13 +1485,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenDest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenDestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1498,7 +1499,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, Lighten(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenDestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1506,7 +1507,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, Lighten(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenDestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1514,7 +1515,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, Lighten(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenDestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1522,7 +1523,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenXor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1530,7 +1531,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 LightenClear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1682,7 +1683,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlaySrc(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1690,7 +1691,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlaySrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1698,7 +1699,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, Overlay(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlaySrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1706,7 +1707,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, Overlay(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlaySrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1714,7 +1715,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, Overlay(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlaySrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1722,13 +1723,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlayDest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlayDestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1736,7 +1737,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, Overlay(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlayDestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1744,7 +1745,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, Overlay(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlayDestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1752,7 +1753,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, Overlay(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlayDestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1760,7 +1761,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlayXor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1768,7 +1769,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 OverlayClear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1920,7 +1921,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightSrc(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1928,7 +1929,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightSrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1936,7 +1937,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, HardLight(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightSrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1944,7 +1945,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, HardLight(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightSrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1952,7 +1953,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, HardLight(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightSrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1960,13 +1961,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightDest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightDestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1974,7 +1975,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, HardLight(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightDestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1982,7 +1983,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, HardLight(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightDestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1990,7 +1991,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, HardLight(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightDestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -1998,7 +1999,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightXor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -2006,7 +2007,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 HardLightClear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 6960c2f1a7..73c835e606 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -13,6 +13,11 @@ // +<# +// Note use of MethodImplOptions.NoInlining. We have tests that are failing on certain architectures when +// AggresiveInlining is used. Confirmed on Intel i7-6600U in 64bit. +#> + using System; using System.Numerics; using System.Runtime.CompilerServices; @@ -24,7 +29,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders <# void GeneratePixelBlenders(string blender) { #> - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>Src(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -32,7 +37,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return source; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>SrcAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -40,7 +45,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(backdrop, source, <#=blender#>(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>SrcOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -48,7 +53,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(backdrop, source, <#=blender#>(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>SrcIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -56,7 +61,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(backdrop, source, <#=blender#>(backdrop, source)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>SrcOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -64,13 +69,13 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>Dest(Vector4 backdrop, Vector4 source, float opacity) { return backdrop; } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>DestAtop(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -78,7 +83,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Atop(source, backdrop, <#=blender#>(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>DestOver(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -86,7 +91,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Over(source, backdrop, <#=blender#>(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>DestIn(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -94,7 +99,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return In(source, backdrop, <#=blender#>(source, backdrop)); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>DestOut(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -102,7 +107,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Out(source, backdrop); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>Xor(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; @@ -110,7 +115,7 @@ namespace SixLabors.ImageSharp.PixelFormats.PixelBlenders return Xor(backdrop, source); } - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(MethodImplOptions.NoInlining)] public static Vector4 <#=blender#>Clear(Vector4 backdrop, Vector4 source, float opacity) { source.W *= opacity; From d46e275072699fde6f4f7260740b96e2c5a6e62c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Tue, 11 Sep 2018 00:31:35 +0200 Subject: [PATCH 054/185] minor code cleanup --- src/ImageSharp/Formats/IImageFormat.cs | 58 +++++++++---------- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 14 +++-- src/ImageSharp/MetaData/ImageMetaData.cs | 10 ++-- 3 files changed, 42 insertions(+), 40 deletions(-) diff --git a/src/ImageSharp/Formats/IImageFormat.cs b/src/ImageSharp/Formats/IImageFormat.cs index 9720352750..94191c1493 100644 --- a/src/ImageSharp/Formats/IImageFormat.cs +++ b/src/ImageSharp/Formats/IImageFormat.cs @@ -6,26 +6,36 @@ using System.Collections.Generic; namespace SixLabors.ImageSharp.Formats { /// - /// Defines the contract for an image format containing metadata with multiple frames. + /// Defines the contract for an image format. /// - /// The type of format metadata. - /// The type of format frame metadata. - public interface IImageFormat : IImageFormat - where TFormatMetaData : class - where TFormatFrameMetaData : class + public interface IImageFormat { /// - /// Creates a default instance of the format frame metadata. + /// Gets the name that describes this image format. /// - /// The . - TFormatFrameMetaData CreateDefaultFormatFrameMetaData(); + string Name { get; } + + /// + /// Gets the default mimetype that the image foramt uses + /// + string DefaultMimeType { get; } + + /// + /// Gets all the mimetypes that have been used by this image foramt. + /// + IEnumerable MimeTypes { get; } + + /// + /// Gets the file extensions this image format commonly uses. + /// + IEnumerable FileExtensions { get; } } /// /// Defines the contract for an image format containing metadata. /// /// The type of format metadata. - public interface IImageFormat : IImageFormat + public interface IImageFormat : IImageFormat where TFormatMetaData : class { /// @@ -36,28 +46,18 @@ namespace SixLabors.ImageSharp.Formats } /// - /// Defines the contract for an image format. + /// Defines the contract for an image format containing metadata with multiple frames. /// - public interface IImageFormat + /// The type of format metadata. + /// The type of format frame metadata. + public interface IImageFormat : IImageFormat + where TFormatMetaData : class + where TFormatFrameMetaData : class { /// - /// Gets the name that describes this image format. - /// - string Name { get; } - - /// - /// Gets the default mimetype that the image foramt uses - /// - string DefaultMimeType { get; } - - /// - /// Gets all the mimetypes that have been used by this image foramt. - /// - IEnumerable MimeTypes { get; } - - /// - /// Gets the file extensions this image format commonly uses. + /// Creates a default instance of the format frame metadata. /// - IEnumerable FileExtensions { get; } + /// The . + TFormatFrameMetaData CreateDefaultFormatFrameMetaData(); } } \ No newline at end of file diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 07d4bdb05e..908a0e6246 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.MetaData /// public sealed class ImageFrameMetaData { - private readonly Dictionary metaData = new Dictionary(); + private readonly Dictionary formatMetaData = new Dictionary(); /// /// Initializes a new instance of the class. @@ -32,9 +32,9 @@ namespace SixLabors.ImageSharp.MetaData { DebugGuard.NotNull(other, nameof(other)); - foreach (KeyValuePair meta in other.metaData) + foreach (KeyValuePair meta in other.formatMetaData) { - this.metaData.Add(meta.Key, meta.Value); + this.formatMetaData.Add(meta.Key, meta.Value); } } @@ -54,13 +54,15 @@ namespace SixLabors.ImageSharp.MetaData /// key is null. /// value is null. /// An element with the same key already exists in the . - public void AddOrUpdateFormatMetaData(IImageFormat key, TFormatFrameMetaData value) + public void AddOrUpdateFormatMetaData( + IImageFormat key, + TFormatFrameMetaData value) where TFormatMetaData : class where TFormatFrameMetaData : class { // Don't think this needs to be threadsafe. Guard.NotNull(value, nameof(value)); - this.metaData[key] = value; + this.formatMetaData[key] = value; } /// @@ -76,7 +78,7 @@ namespace SixLabors.ImageSharp.MetaData where TFormatMetaData : class where TFormatFrameMetaData : class { - if (this.metaData.TryGetValue(key, out object meta)) + if (this.formatMetaData.TryGetValue(key, out object meta)) { return (TFormatFrameMetaData)meta; } diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index aa084728ca..74c00cf8a5 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.MetaData /// public const double DefaultVerticalResolution = 96; - private readonly Dictionary metaData = new Dictionary(); + private readonly Dictionary formatMetaData = new Dictionary(); private double horizontalResolution; private double verticalResolution; @@ -52,9 +52,9 @@ namespace SixLabors.ImageSharp.MetaData this.VerticalResolution = other.VerticalResolution; this.ResolutionUnits = other.ResolutionUnits; - foreach (KeyValuePair meta in other.metaData) + foreach (KeyValuePair meta in other.formatMetaData) { - this.metaData.Add(meta.Key, meta.Value); + this.formatMetaData.Add(meta.Key, meta.Value); } foreach (ImageProperty property in other.Properties) @@ -145,7 +145,7 @@ namespace SixLabors.ImageSharp.MetaData { // Don't think this needs to be threadsafe. Guard.NotNull(value, nameof(value)); - this.metaData[key] = value; + this.formatMetaData[key] = value; } /// @@ -159,7 +159,7 @@ namespace SixLabors.ImageSharp.MetaData public TFormatMetaData GetOrAddFormatMetaData(IImageFormat key) where TFormatMetaData : class { - if (this.metaData.TryGetValue(key, out object meta)) + if (this.formatMetaData.TryGetValue(key, out object meta)) { return (TFormatMetaData)meta; } From 8ccea04cdb122e72be79d1453632ea1d37162d37 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 11 Sep 2018 11:41:52 +0100 Subject: [PATCH 055/185] Use metadata as fallback forpng encoder options. --- .../Formats/Png/IPngEncoderOptions.cs | 18 ++---- src/ImageSharp/Formats/Png/PngChunkType.cs | 52 ++++++++-------- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 58 ++++++++++++++---- src/ImageSharp/Formats/Png/PngEncoder.cs | 14 ++--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 61 ++++++++++--------- src/ImageSharp/Formats/Png/PngMetaData.cs | 18 +++++- 6 files changed, 129 insertions(+), 92 deletions(-) diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index f3231fa22a..77bc9f7a05 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -14,12 +14,12 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets the number of bits per sample or per palette index (not per pixel). /// Not all values are allowed for all values. /// - PngBitDepth BitDepth { get; } + PngBitDepth? BitDepth { get; } /// /// Gets the color type /// - PngColorType ColorType { get; } + PngColorType? ColorType { get; } /// /// Gets the filter method. @@ -33,15 +33,13 @@ namespace SixLabors.ImageSharp.Formats.Png int CompressionLevel { get; } /// - /// Gets the gamma value, that will be written - /// the the stream, when the property - /// is set to true. The default value is 2.2F. + /// Gets the gamma value, that will be written the the image. /// /// The gamma value of the image. - float Gamma { get; } + float? Gamma { get; } /// - /// Gets quantizer for reducing the color count. + /// Gets the quantizer for reducing the color count. /// IQuantizer Quantizer { get; } @@ -49,11 +47,5 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets the transparency threshold. /// byte Threshold { get; } - - /// - /// Gets a value indicating whether this instance should write - /// gamma information to the stream. The default value is false. - /// - bool WriteGamma { get; } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs index e0844ca6b8..7654c17014 100644 --- a/src/ImageSharp/Formats/Png/PngChunkType.cs +++ b/src/ImageSharp/Formats/Png/PngChunkType.cs @@ -8,58 +8,58 @@ namespace SixLabors.ImageSharp.Formats.Png /// internal enum PngChunkType : uint { - /// - /// The first chunk in a png file. Can only exists once. Contains - /// common information like the width and the height of the image or - /// the used compression method. - /// - Header = 0x49484452U, // IHDR - - /// - /// The PLTE chunk contains from 1 to 256 palette entries, each a three byte - /// series in the RGB format. - /// - Palette = 0x504C5445U, // PLTE - /// /// The IDAT chunk contains the actual image data. The image can contains more /// than one chunk of this type. All chunks together are the whole image. /// - Data = 0x49444154U, // IDAT + Data = 0x49444154U, /// /// This chunk must appear last. It marks the end of the PNG data stream. /// The chunk's data field is empty. /// - End = 0x49454E44U, // IEND + End = 0x49454E44U, /// - /// This chunk specifies that the image uses simple transparency: - /// either alpha values associated with palette entries (for indexed-color images) - /// or a single transparent color (for grayscale and true color images). + /// The first chunk in a png file. Can only exists once. Contains + /// common information like the width and the height of the image or + /// the used compression method. /// - PaletteAlpha = 0x74524E53U, // tRNS + Header = 0x49484452U, /// - /// Textual information that the encoder wishes to record with the image can be stored in - /// tEXt chunks. Each tEXt chunk contains a keyword and a text string. + /// The PLTE chunk contains from 1 to 256 palette entries, each a three byte + /// series in the RGB format. + /// + Palette = 0x504C5445U, + + /// + /// The eXIf data chunk which contains the Exif profile. /// - Text = 0x74455874U, // tEXt + Exif = 0x65584966U, /// /// This chunk specifies the relationship between the image samples and the desired /// display output intensity. /// - Gamma = 0x67414D41U, // gAMA + Gamma = 0x67414D41U, /// /// The pHYs chunk specifies the intended pixel size or aspect ratio for display of the image. /// - Physical = 0x70485973U, // pHYs + Physical = 0x70485973U, /// - /// The data chunk which contains the Exif profile. + /// Textual information that the encoder wishes to record with the image can be stored in + /// tEXt chunks. Each tEXt chunk contains a keyword and a text string. + /// + Text = 0x74455874U, + + /// + /// This chunk specifies that the image uses simple transparency: + /// either alpha values associated with palette entries (for indexed-color images) + /// or a single transparent color (for grayscale and true color images). /// - Exif = 0x65584966U // eXIf + PaletteAlpha = 0x74524E53U } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index be1914174b..4bc4833011 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -216,7 +216,9 @@ namespace SixLabors.ImageSharp.Formats.Png public Image Decode(Stream stream) where TPixel : struct, IPixel { - var metadata = new ImageMetaData(); + var metaData = new ImageMetaData(); + var pngMetaData = new PngMetaData(); + metaData.AddOrUpdateFormatMetaData(PngFormat.Instance, pngMetaData); this.currentStream = stream; this.currentStream.Skip(8); Image image = null; @@ -231,16 +233,19 @@ namespace SixLabors.ImageSharp.Formats.Png switch (chunk.Type) { case PngChunkType.Header: - this.ReadHeaderChunk(chunk.Data.Array); + this.ReadHeaderChunk(pngMetaData, chunk.Data.Array); this.ValidateHeader(); break; case PngChunkType.Physical: - this.ReadPhysicalChunk(metadata, chunk.Data.GetSpan()); + this.ReadPhysicalChunk(metaData, chunk.Data.GetSpan()); + break; + case PngChunkType.Gamma: + this.ReadGammaChunk(pngMetaData, chunk.Data.GetSpan()); break; case PngChunkType.Data: if (image is null) { - this.InitializeImage(metadata, out image); + this.InitializeImage(metaData, out image); } deframeStream.AllocateNewBytes(chunk.Length); @@ -259,14 +264,14 @@ namespace SixLabors.ImageSharp.Formats.Png this.AssignTransparentMarkers(alpha); break; case PngChunkType.Text: - this.ReadTextChunk(metadata, chunk.Data.Array, chunk.Length); + this.ReadTextChunk(metaData, chunk.Data.Array, chunk.Length); break; case PngChunkType.Exif: if (!this.ignoreMetadata) { byte[] exifData = new byte[chunk.Length]; Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length); - metadata.ExifProfile = new ExifProfile(exifData); + metaData.ExifProfile = new ExifProfile(exifData); } break; @@ -302,7 +307,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The containing image data. public IImageInfo Identify(Stream stream) { - var metadata = new ImageMetaData(); + var metaData = new ImageMetaData(); + var pngMetaData = new PngMetaData(); + metaData.AddOrUpdateFormatMetaData(PngFormat.Instance, pngMetaData); this.currentStream = stream; this.currentStream.Skip(8); try @@ -314,17 +321,20 @@ namespace SixLabors.ImageSharp.Formats.Png switch (chunk.Type) { case PngChunkType.Header: - this.ReadHeaderChunk(chunk.Data.Array); + this.ReadHeaderChunk(pngMetaData, chunk.Data.Array); this.ValidateHeader(); break; case PngChunkType.Physical: - this.ReadPhysicalChunk(metadata, chunk.Data.GetSpan()); + this.ReadPhysicalChunk(metaData, chunk.Data.GetSpan()); + break; + case PngChunkType.Gamma: + this.ReadGammaChunk(pngMetaData, chunk.Data.GetSpan()); break; case PngChunkType.Data: this.SkipChunkDataAndCrc(chunk); break; case PngChunkType.Text: - this.ReadTextChunk(metadata, chunk.Data.Array, chunk.Length); + this.ReadTextChunk(metaData, chunk.Data.Array, chunk.Length); break; case PngChunkType.End: this.isEndChunkReached = true; @@ -348,7 +358,7 @@ namespace SixLabors.ImageSharp.Formats.Png throw new ImageFormatException("PNG Image does not contain a header chunk"); } - return new ImageInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), this.header.Width, this.header.Height, metadata); + return new ImageInfo(new PixelTypeInfo(this.CalculateBitsPerPixel()), this.header.Width, this.header.Height, metaData); } /// @@ -427,6 +437,18 @@ namespace SixLabors.ImageSharp.Formats.Png metadata.VerticalResolution = vResolution; } + /// + /// Reads the data chunk containing gamma data. + /// + /// The metadata to read to. + /// The data containing physical data. + private void ReadGammaChunk(PngMetaData pngMetadata, ReadOnlySpan data) + { + // The value is encoded as a 4-byte unsigned integer, representing gamma times 100000. + // For example, a gamma of 1/2.2 would be stored as 45455. + pngMetadata.Gamma = BinaryPrimitives.ReadUInt32BigEndian(data) / 100_000F; + } + /// /// Initializes the image and various buffers needed for processing /// @@ -1267,17 +1289,27 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Reads a header chunk from the data. /// + /// The png metadata. /// The containing data. - private void ReadHeaderChunk(ReadOnlySpan data) + private void ReadHeaderChunk(PngMetaData pngMetaData, ReadOnlySpan data) { + byte bitDepth = data[8]; this.header = new PngHeader( width: BinaryPrimitives.ReadInt32BigEndian(data.Slice(0, 4)), height: BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4)), - bitDepth: data[8], + bitDepth: bitDepth, colorType: (PngColorType)data[9], compressionMethod: data[10], filterMethod: data[11], interlaceMethod: (PngInterlaceMode)data[12]); + + // TODO: Figure out how we can determine the number of colors and support more bit depths. + if (bitDepth == 8 || bitDepth == 16) + { + pngMetaData.BitDepth = (PngBitDepth)bitDepth; + } + + pngMetaData.ColorType = this.header.ColorType; } /// diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 109e6ad770..435d0abbc9 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -4,6 +4,7 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp.Formats.Png @@ -17,12 +18,12 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets or sets the number of bits per sample or per palette index (not per pixel). /// Not all values are allowed for all values. /// - public PngBitDepth BitDepth { get; set; } = PngBitDepth.Bit8; + public PngBitDepth? BitDepth { get; set; } /// /// Gets or sets the color type. /// - public PngColorType ColorType { get; set; } = PngColorType.RgbWithAlpha; + public PngColorType? ColorType { get; set; } /// /// Gets or sets the filter method. @@ -36,18 +37,15 @@ namespace SixLabors.ImageSharp.Formats.Png public int CompressionLevel { get; set; } = 6; /// - /// Gets or sets the gamma value, that will be written - /// the the stream, when the property - /// is set to true. The default value is 2.2F. + /// Gets or sets the gamma value, that will be written the the image. /// - /// The gamma value of the image. - public float Gamma { get; set; } = 2.2F; + public float? Gamma { get; set; } /// /// Gets or sets quantizer for reducing the color count. /// Defaults to the /// - public IQuantizer Quantizer { get; set; } = new WuQuantizer(); + public IQuantizer Quantizer { get; set; } = KnownQuantizers.Wu; /// /// Gets or sets the transparency threshold. diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index ffe29aecae..9d9de71b14 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -4,7 +4,6 @@ using System; using System.Buffers.Binary; using System.IO; -using System.Linq; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Png.Filters; @@ -45,49 +44,49 @@ namespace SixLabors.ImageSharp.Formats.Png private readonly Crc32 crc = new Crc32(); /// - /// The png bit depth + /// The png filter method. /// - private readonly PngBitDepth pngBitDepth; + private readonly PngFilterMethod pngFilterMethod; /// - /// Gets or sets a value indicating whether to use 16 bit encoding for supported color types. + /// The quantizer for reducing the color count. /// - private readonly bool use16Bit; + private readonly IQuantizer quantizer; /// - /// The png color type. + /// Gets or sets the CompressionLevel value /// - private readonly PngColorType pngColorType; + private readonly int compressionLevel; /// - /// The png filter method. + /// Gets or sets the alpha threshold value /// - private readonly PngFilterMethod pngFilterMethod; + private readonly byte threshold; /// - /// The quantizer for reducing the color count. + /// Gets or sets a value indicating whether to write the gamma chunk /// - private readonly IQuantizer quantizer; + private bool writeGamma; /// - /// Gets or sets the CompressionLevel value + /// The png bit depth /// - private readonly int compressionLevel; + private PngBitDepth? pngBitDepth; /// - /// Gets or sets the Gamma value + /// Gets or sets a value indicating whether to use 16 bit encoding for supported color types. /// - private readonly float gamma; + private bool use16Bit; /// - /// Gets or sets the Threshold value + /// The png color type. /// - private readonly byte threshold; + private PngColorType? pngColorType; /// - /// Gets or sets a value indicating whether to Write Gamma + /// Gets or sets the Gamma value /// - private readonly bool writeGamma; + private float? gamma; /// /// The image width. @@ -158,14 +157,12 @@ namespace SixLabors.ImageSharp.Formats.Png { this.memoryAllocator = memoryAllocator; this.pngBitDepth = options.BitDepth; - this.use16Bit = this.pngBitDepth.Equals(PngBitDepth.Bit16); this.pngColorType = options.ColorType; this.pngFilterMethod = options.FilterMethod; this.compressionLevel = options.CompressionLevel; this.gamma = options.Gamma; this.quantizer = options.Quantizer; this.threshold = options.Threshold; - this.writeGamma = options.WriteGamma; } /// @@ -183,6 +180,16 @@ namespace SixLabors.ImageSharp.Formats.Png this.width = image.Width; this.height = image.Height; + // Always take the encoder options over the metadata values. + PngMetaData pngMetaData = image.MetaData.GetOrAddFormatMetaData(PngFormat.Instance); + this.gamma = this.gamma ?? pngMetaData.Gamma; + this.writeGamma = this.gamma > 0; + this.pngColorType = this.pngColorType ?? pngMetaData.ColorType; + + // TODO: We don't take full advantage of this information yet. + this.pngBitDepth = this.pngBitDepth ?? pngMetaData.BitDepth; + this.use16Bit = this.pngBitDepth.Equals(PngBitDepth.Bit16); + stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); QuantizedFrame quantized = null; @@ -217,7 +224,7 @@ namespace SixLabors.ImageSharp.Formats.Png width: image.Width, height: image.Height, bitDepth: this.bitDepth, - colorType: this.pngColorType, + colorType: this.pngColorType.Value, compressionMethod: 0, // None filterMethod: 0, interlaceMethod: 0); // TODO: Can't write interlaced yet. @@ -781,10 +788,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// Writes the chunk end to the stream. /// /// The containing image data. - private void WriteEndChunk(Stream stream) - { - this.WriteChunk(stream, PngChunkType.End, null); - } + private void WriteEndChunk(Stream stream) => this.WriteChunk(stream, PngChunkType.End, null); /// /// Writes a chunk to the stream. @@ -792,10 +796,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// The to write to. /// The type of chunk to write. /// The containing data. - private void WriteChunk(Stream stream, PngChunkType type, byte[] data) - { - this.WriteChunk(stream, type, data, 0, data?.Length ?? 0); - } + private void WriteChunk(Stream stream, PngChunkType type, byte[] data) => this.WriteChunk(stream, type, data, 0, data?.Length ?? 0); /// /// Writes a chunk of a specified length to the stream at the given offset. diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 90dbb83b6f..1eb3cdad6a 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -8,6 +8,20 @@ namespace SixLabors.ImageSharp.Formats.Png /// public class PngMetaData { - // TODO: Analyse what properties we would like to preserve. + /// + /// Gets or sets the number of bits per sample or per palette index (not per pixel). + /// Not all values are allowed for all values. + /// + public PngBitDepth BitDepth { get; set; } = PngBitDepth.Bit8; + + /// + /// Gets or sets the color type. + /// + public PngColorType ColorType { get; set; } = PngColorType.RgbWithAlpha; + + /// + /// Gets or sets the gamma value for the image. + /// + public float Gamma { get; set; } } -} +} \ No newline at end of file From 551c03f16a33b7a1a3f9e6446e9119519fe6446c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 11 Sep 2018 15:58:42 +0100 Subject: [PATCH 056/185] Preserve BmpBitsPerPixel --- src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs | 6 +-- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 17 +++++-- src/ImageSharp/Formats/Bmp/BmpEncoder.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 17 ++++--- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 7 ++- .../Formats/Bmp/IBmpEncoderOptions.cs | 2 +- .../Formats/Bmp/BmpEncoderTests.cs | 45 ++++++++++++++----- tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Bmp/rgb32.bmp | 3 ++ 9 files changed, 71 insertions(+), 29 deletions(-) create mode 100644 tests/Images/Input/Bmp/rgb32.bmp diff --git a/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs b/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs index 0029a6b68d..618999c87d 100644 --- a/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs +++ b/src/ImageSharp/Formats/Bmp/BmpBitsPerPixel.cs @@ -6,16 +6,16 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Enumerates the available bits per pixel for bitmap. /// - public enum BmpBitsPerPixel + public enum BmpBitsPerPixel : short { /// /// 24 bits per pixel. Each pixel consists of 3 bytes. /// - Pixel24 = 3, + Pixel24 = 24, /// /// 32 bits per pixel. Each pixel consists of 4 bytes. /// - Pixel32 = 4 + Pixel32 = 32 } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 385c79896e..3bb44f1d06 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -536,6 +536,17 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.metaData = meta; + short bitsPerPixel = this.infoHeader.BitsPerPixel; + var bmpMetaData = new BmpMetaData(); + this.metaData.AddOrUpdateFormatMetaData(BmpFormat.Instance, bmpMetaData); + + // We can only encode at these bit rates so far. + if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24) + || bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel32)) + { + bmpMetaData.BitsPerPixel = (BmpBitsPerPixel)bitsPerPixel; + } + // skip the remaining header because we can't read those parts this.stream.Skip(skipAmount); } @@ -581,9 +592,9 @@ namespace SixLabors.ImageSharp.Formats.Bmp if (this.infoHeader.ClrUsed == 0) { - if (this.infoHeader.BitsPerPixel == 1 || - this.infoHeader.BitsPerPixel == 4 || - this.infoHeader.BitsPerPixel == 8) + if (this.infoHeader.BitsPerPixel == 1 + || this.infoHeader.BitsPerPixel == 4 + || this.infoHeader.BitsPerPixel == 8) { colorMapSize = (int)Math.Pow(2, this.infoHeader.BitsPerPixel) * 4; } diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs index 23b01ae9e8..b1a66accec 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoder.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoder.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Gets or sets the number of bits per pixel. /// - public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; + public BmpBitsPerPixel? BitsPerPixel { get; set; } /// public void Encode(Image image, Stream stream) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index b49b8a8959..7a09a47f78 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -21,10 +21,10 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// private int padding; - private readonly BmpBitsPerPixel bitsPerPixel; - private readonly MemoryAllocator memoryAllocator; + private BmpBitsPerPixel? bitsPerPixel; + /// /// Initializes a new instance of the class. /// @@ -48,10 +48,12 @@ namespace SixLabors.ImageSharp.Formats.Bmp Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - // Cast to int will get the bytes per pixel - short bpp = (short)(8 * (int)this.bitsPerPixel); + BmpMetaData bmpMetaData = image.MetaData.GetOrAddFormatMetaData(BmpFormat.Instance); + this.bitsPerPixel = this.bitsPerPixel ?? bmpMetaData.BitsPerPixel; + + short bpp = (short)this.bitsPerPixel; int bytesPerLine = 4 * (((image.Width * bpp) + 31) / 32); - this.padding = bytesPerLine - (image.Width * (int)this.bitsPerPixel); + this.padding = bytesPerLine - (int)(image.Width * (bpp / 8F)); // Set Resolution. ImageMetaData meta = image.MetaData; @@ -145,10 +147,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp } } - private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel) - { - return this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding); - } + private IManagedByteBuffer AllocateRow(int width, int bytesPerPixel) => this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, bytesPerPixel, this.padding); /// /// Writes the 32bit color palette to the stream. diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs index aa60f38662..3d678c13e1 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs @@ -8,6 +8,11 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// public class BmpMetaData { - // TODO: Analyse what properties we would like to preserve. + /// + /// Gets or sets the number of bits per pixel. + /// + public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; + + // TODO: Colors used once we support encoding palette bmps. } } diff --git a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs index 56952f0356..f62504d08f 100644 --- a/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs +++ b/src/ImageSharp/Formats/Bmp/IBmpEncoderOptions.cs @@ -12,6 +12,6 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Gets the number of bits per pixel. /// - BmpBitsPerPixel BitsPerPixel { get; } + BmpBitsPerPixel? BitsPerPixel { get; } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index d887d23ade..c75c656919 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -28,10 +28,14 @@ namespace SixLabors.ImageSharp.Tests { TestImages.Bmp.RLE, 2835, 2835, PixelResolutionUnit.PixelsPerMeter } }; - public BmpEncoderTests(ITestOutputHelper output) + public static readonly TheoryData BmpBitsPerPixelFiles = + new TheoryData { - this.Output = output; - } + { TestImages.Bmp.Car, BmpBitsPerPixel.Pixel24 }, + { TestImages.Bmp.Bit32Rgb, BmpBitsPerPixel.Pixel32 } + }; + + public BmpEncoderTests(ITestOutputHelper output) => this.Output = output; private ITestOutputHelper Output { get; } @@ -61,13 +65,35 @@ namespace SixLabors.ImageSharp.Tests } [Theory] - [WithTestPatternImages(nameof(BitsPerPixel), 24, 24, PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24)] - public void Encode_IsNotBoundToSinglePixelType(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) - where TPixel : struct, IPixel + [MemberData(nameof(BmpBitsPerPixelFiles))] + public void Encode_PreserveBitsPerPixel(string imagePath, BmpBitsPerPixel bmpBitsPerPixel) { - TestBmpEncoderCore(provider, bitsPerPixel); + var options = new BmpEncoder(); + + var testFile = TestFile.Create(imagePath); + using (Image input = testFile.CreateImage()) + { + using (var memStream = new MemoryStream()) + { + input.Save(memStream, options); + + memStream.Position = 0; + using (var output = Image.Load(memStream)) + { + BmpMetaData meta = output.MetaData.GetOrAddFormatMetaData(BmpFormat.Instance); + + Assert.Equal(bmpBitsPerPixel, meta.BitsPerPixel); + } + } + } } + + [Theory] + [WithTestPatternImages(nameof(BitsPerPixel), 24, 24, PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24)] + public void Encode_IsNotBoundToSinglePixelType(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) + where TPixel : struct, IPixel => TestBmpEncoderCore(provider, bitsPerPixel); + [Theory] [WithTestPatternImages(nameof(BitsPerPixel), 48, 24, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(BitsPerPixel), 47, 8, PixelTypes.Rgba32)] @@ -75,10 +101,7 @@ namespace SixLabors.ImageSharp.Tests [WithSolidFilledImages(nameof(BitsPerPixel), 1, 1, 255, 100, 50, 255, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(BitsPerPixel), 7, 5, PixelTypes.Rgba32)] public void Encode_WorksWithDifferentSizes(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) - where TPixel : struct, IPixel - { - TestBmpEncoderCore(provider, bitsPerPixel); - } + where TPixel : struct, IPixel => TestBmpEncoderCore(provider, bitsPerPixel); private static void TestBmpEncoderCore(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) where TPixel : struct, IPixel diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index df015f7556..acfad042eb 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -178,6 +178,7 @@ namespace SixLabors.ImageSharp.Tests public const string Bit8Inverted = "Bmp/test8-inverted.bmp"; public const string Bit16 = "Bmp/test16.bmp"; public const string Bit16Inverted = "Bmp/test16-inverted.bmp"; + public const string Bit32Rgb = "Bmp/rgb32.bmp"; public static readonly string[] All = { diff --git a/tests/Images/Input/Bmp/rgb32.bmp b/tests/Images/Input/Bmp/rgb32.bmp new file mode 100644 index 0000000000..bc4c47c9e5 --- /dev/null +++ b/tests/Images/Input/Bmp/rgb32.bmp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b4c79cb8ffd2f1c096af27f9d82b5feaa0aa2cb049c791e0f6251de0435066e5 +size 32566 From bd5b0c07eb0d2703b45897746463e9460f33c0d2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 11 Sep 2018 19:38:23 +0100 Subject: [PATCH 057/185] Png now correctly encodes 1, 2, 4 bit images --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 18 ++++--- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 4 +- src/ImageSharp/Formats/Png/PngBitDepth.cs | 15 ++++++ src/ImageSharp/Formats/Png/PngDecoderCore.cs | 11 ++-- src/ImageSharp/Formats/Png/PngEncoder.cs | 3 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 51 +++++++++++++++---- .../Formats/Bmp/BmpEncoderTests.cs | 1 - .../Formats/Png/PngEncoderTests.cs | 31 +++++++++++ 9 files changed, 103 insertions(+), 33 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 3c48488ecc..cacaca0bb7 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -36,10 +36,15 @@ namespace SixLabors.ImageSharp /// The /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetBitsNeededForColorDepth(int colors) - { - return Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2))); - } + public static int GetBitsNeededForColorDepth(int colors) => Math.Max(1, (int)Math.Ceiling(Math.Log(colors, 2))); + + /// + /// Returns how many colors will be created by the specified number of bits. + /// + /// The bit depth. + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int GetColorCountForBitDepth(int bitDepth) => (int)Math.Pow(2, bitDepth); /// /// Implementation of 1D Gaussian G(x) function @@ -132,10 +137,7 @@ namespace SixLabors.ImageSharp /// The bounding . /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) - { - return new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); - } + public static Rectangle GetBoundingRectangle(Point topLeft, Point bottomRight) => new Rectangle(topLeft.X, topLeft.Y, bottomRight.X - topLeft.X, bottomRight.Y - topLeft.Y); /// /// Finds the bounding rectangle based on the first instance of any color component other diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 3bb44f1d06..a574d5178d 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -596,7 +596,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp || this.infoHeader.BitsPerPixel == 4 || this.infoHeader.BitsPerPixel == 8) { - colorMapSize = (int)Math.Pow(2, this.infoHeader.BitsPerPixel) * 4; + colorMapSize = ImageMaths.GetColorCountForBitDepth(this.infoHeader.BitsPerPixel) * 4; } } else diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 7a880b0f96..f2e0eab5c2 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.gifMetaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + this.gifMetaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; bool useGlobalTable = this.colorTableMode.Equals(GifColorTableMode.Global); @@ -412,7 +412,7 @@ namespace SixLabors.ImageSharp.Formats.Gif int pixelCount = image.Palette.Length; // The maximium number of colors for the bit depth - int colorTableLength = (int)Math.Pow(2, this.bitDepth) * 3; + int colorTableLength = ImageMaths.GetColorCountForBitDepth(this.bitDepth) * 3; Rgb24 rgb = default; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) diff --git a/src/ImageSharp/Formats/Png/PngBitDepth.cs b/src/ImageSharp/Formats/Png/PngBitDepth.cs index 0c22a4c913..396f2c1608 100644 --- a/src/ImageSharp/Formats/Png/PngBitDepth.cs +++ b/src/ImageSharp/Formats/Png/PngBitDepth.cs @@ -9,6 +9,21 @@ namespace SixLabors.ImageSharp.Formats.Png /// public enum PngBitDepth { + /// + /// 1 bit per sample or per palette index (not per pixel). + /// + Bit1 = 1, + + /// + /// 2 bits per sample or per palette index (not per pixel). + /// + Bit2 = 2, + + /// + /// 4 bits per sample or per palette index (not per pixel). + /// + Bit4 = 4, + /// /// 8 bits per sample or per palette index (not per pixel). /// diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 4bc4833011..3daee991c9 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -730,7 +730,7 @@ namespace SixLabors.ImageSharp.Formats.Png { case PngColorType.Grayscale: - int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); + int factor = 255 / (ImageMaths.GetColorCountForBitDepth(this.header.BitDepth) - 1); if (!this.hasTrans) { @@ -952,7 +952,7 @@ namespace SixLabors.ImageSharp.Formats.Png { case PngColorType.Grayscale: - int factor = 255 / ((int)Math.Pow(2, this.header.BitDepth) - 1); + int factor = 255 / (ImageMaths.GetColorCountForBitDepth(this.header.BitDepth) - 1); if (!this.hasTrans) { @@ -1303,12 +1303,7 @@ namespace SixLabors.ImageSharp.Formats.Png filterMethod: data[11], interlaceMethod: (PngInterlaceMode)data[12]); - // TODO: Figure out how we can determine the number of colors and support more bit depths. - if (bitDepth == 8 || bitDepth == 16) - { - pngMetaData.BitDepth = (PngBitDepth)bitDepth; - } - + pngMetaData.BitDepth = (PngBitDepth)bitDepth; pngMetaData.ColorType = this.header.ColorType; } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 435d0abbc9..05d687a888 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -4,7 +4,6 @@ using System.IO; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp.Formats.Png @@ -45,7 +44,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets or sets quantizer for reducing the color count. /// Defaults to the /// - public IQuantizer Quantizer { get; set; } = KnownQuantizers.Wu; + public IQuantizer Quantizer { get; set; } /// /// Gets or sets the transparency threshold. diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 9d9de71b14..20fc8b8e36 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -48,11 +48,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly PngFilterMethod pngFilterMethod; - /// - /// The quantizer for reducing the color count. - /// - private readonly IQuantizer quantizer; - /// /// Gets or sets the CompressionLevel value /// @@ -63,6 +58,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly byte threshold; + /// + /// The quantizer for reducing the color count. + /// + private IQuantizer quantizer; + /// /// Gets or sets a value indicating whether to write the gamma chunk /// @@ -185,8 +185,6 @@ namespace SixLabors.ImageSharp.Formats.Png this.gamma = this.gamma ?? pngMetaData.Gamma; this.writeGamma = this.gamma > 0; this.pngColorType = this.pngColorType ?? pngMetaData.ColorType; - - // TODO: We don't take full advantage of this information yet. this.pngBitDepth = this.pngBitDepth ?? pngMetaData.BitDepth; this.use16Bit = this.pngBitDepth.Equals(PngBitDepth.Bit16); @@ -196,17 +194,27 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan quantizedPixelsSpan = default; if (this.pngColorType == PngColorType.Palette) { + byte bits; + + // Use the metadata to determine what quantization depth to use if no quantizer has been set. + if (this.quantizer == null) + { + bits = (byte)Math.Min(8u, (short)this.pngBitDepth); + int colorSize = ImageMaths.GetColorCountForBitDepth(bits); + this.quantizer = new WuQuantizer(colorSize); + } + // Create quantized frame returning the palette and set the bit depth. quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); quantizedPixelsSpan = quantized.GetPixelSpan(); - byte bits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); + bits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk if (bits == 3) { bits = 4; } - else if (bits >= 5 || bits <= 7) + else if (bits >= 5 && bits <= 7) { bits = 8; } @@ -556,7 +564,7 @@ namespace SixLabors.ImageSharp.Formats.Png byte pixelCount = palette.Length.ToByte(); // Get max colors for bit depth. - int colorTableLength = (int)Math.Pow(2, header.BitDepth) * 3; + int colorTableLength = ImageMaths.GetColorCountForBitDepth(header.BitDepth) * 3; Rgba32 rgba = default; bool anyAlpha = false; @@ -700,7 +708,7 @@ namespace SixLabors.ImageSharp.Formats.Png private void WriteDataChunks(ImageFrame pixels, ReadOnlySpan quantizedPixelsSpan, Stream stream) where TPixel : struct, IPixel { - this.bytesPerScanline = this.width * this.bytesPerPixel; + this.bytesPerScanline = this.CalculateScanlineLength(this.width); int resultLength = this.bytesPerScanline + 1; this.previousScanline = this.memoryAllocator.AllocateManagedByteBuffer(this.bytesPerScanline, AllocationOptions.Clean); @@ -828,5 +836,26 @@ namespace SixLabors.ImageSharp.Formats.Png stream.Write(this.buffer, 0, 4); // write the crc } + + /// + /// Calculates the scanline length. + /// + /// The width of the row. + /// + /// The representing the length. + /// + private int CalculateScanlineLength(int width) + { + int mod = this.bitDepth == 16 ? 16 : 8; + int scanlineLength = width * this.bitDepth * this.bytesPerPixel; + + int amount = scanlineLength % mod; + if (amount != 0) + { + scanlineLength += mod - amount; + } + + return scanlineLength / mod; + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index c75c656919..311b28f2d5 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -88,7 +88,6 @@ namespace SixLabors.ImageSharp.Tests } } - [Theory] [WithTestPatternImages(nameof(BitsPerPixel), 24, 24, PixelTypes.Rgba32 | PixelTypes.Bgra32 | PixelTypes.Rgb24)] public void Encode_IsNotBoundToSinglePixelType(TestImageProvider provider, BmpBitsPerPixel bitsPerPixel) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 62de45064a..c9435a37dc 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -23,6 +23,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png // The images are an exact match. Maybe the submodule isn't updating? private const float ToleranceThresholdForPaletteEncoder = 1.3F / 100; + public static readonly TheoryData PngBitDepthFiles = + new TheoryData + { + { TestImages.Png.Rgb48Bpp, PngBitDepth.Bit16 }, + { TestImages.Png.Bpp1, PngBitDepth.Bit1 } + }; + /// /// All types except Palette /// @@ -290,5 +297,29 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } } + + [Theory] + [MemberData(nameof(PngBitDepthFiles))] + public void Encode_PreserveBits(string imagePath, PngBitDepth pngBitDepth) + { + var options = new PngEncoder(); + + var testFile = TestFile.Create(imagePath); + using (Image input = testFile.CreateImage()) + { + using (var memStream = new MemoryStream()) + { + input.Save(memStream, options); + + memStream.Position = 0; + using (var output = Image.Load(memStream)) + { + PngMetaData meta = output.MetaData.GetOrAddFormatMetaData(PngFormat.Instance); + + Assert.Equal(pngBitDepth, meta.BitDepth); + } + } + } + } } } \ No newline at end of file From 06b9c542488ecab108128dfde7b74bb9b15647c0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 12 Sep 2018 08:30:42 +0100 Subject: [PATCH 058/185] Simplify metadata API --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 2 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 3 +-- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 2 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 15 ++++------- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 6 ++--- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 6 ++--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 25 ++----------------- src/ImageSharp/MetaData/ImageMetaData.cs | 21 ++-------------- .../Formats/Bmp/BmpEncoderTests.cs | 2 +- .../Formats/Gif/GifEncoderTests.cs | 10 ++++---- .../Formats/Png/PngEncoderTests.cs | 4 +-- .../MetaData/ImageFrameMetaDataTests.cs | 14 ++++------- 13 files changed, 31 insertions(+), 81 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index cacaca0bb7..c15e0a7329 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp /// The bit depth. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static int GetColorCountForBitDepth(int bitDepth) => (int)Math.Pow(2, bitDepth); + public static int GetColorCountForBitDepth(int bitDepth) => 1 << bitDepth; /// /// Implementation of 1D Gaussian G(x) function diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index a574d5178d..71852acddd 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -537,8 +537,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.metaData = meta; short bitsPerPixel = this.infoHeader.BitsPerPixel; - var bmpMetaData = new BmpMetaData(); - this.metaData.AddOrUpdateFormatMetaData(BmpFormat.Instance, bmpMetaData); + var bmpMetaData = this.metaData.GetFormatMetaData(BmpFormat.Instance); // We can only encode at these bit rates so far. if (bitsPerPixel.Equals((short)BmpBitsPerPixel.Pixel24) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 7a09a47f78..4ffaf39506 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - BmpMetaData bmpMetaData = image.MetaData.GetOrAddFormatMetaData(BmpFormat.Instance); + BmpMetaData bmpMetaData = image.MetaData.GetFormatMetaData(BmpFormat.Instance); this.bitsPerPixel = this.bitsPerPixel ?? bmpMetaData.BitsPerPixel; short bpp = (short)this.bitsPerPixel; diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index f503812641..207f126f9e 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -164,7 +164,6 @@ namespace SixLabors.ImageSharp.Formats.Gif this.globalColorTable?.Dispose(); } - image?.MetaData.AddOrUpdateFormatMetaData(GifFormat.Instance, this.gifMetaData); return image; } @@ -224,7 +223,6 @@ namespace SixLabors.ImageSharp.Formats.Gif this.globalColorTable?.Dispose(); } - this.metaData.AddOrUpdateFormatMetaData(GifFormat.Instance, this.gifMetaData); return new ImageInfo( new PixelTypeInfo(this.logicalScreenDescriptor.BitsPerPixel), this.logicalScreenDescriptor.Width, @@ -542,7 +540,7 @@ namespace SixLabors.ImageSharp.Formats.Gif [MethodImpl(MethodImplOptions.AggressiveInlining)] private void SetFrameMetaData(ImageFrameMetaData meta) { - var gifMeta = new GifFrameMetaData(); + GifFrameMetaData gifMeta = meta.GetFormatMetaData(GifFormat.Instance); if (this.graphicsControlExtension.DelayTime > 0) { gifMeta.FrameDelay = this.graphicsControlExtension.DelayTime; @@ -561,7 +559,6 @@ namespace SixLabors.ImageSharp.Formats.Gif } gifMeta.DisposalMethod = this.graphicsControlExtension.DisposalMethod; - meta.AddOrUpdateFormatMetaData(GifFormat.Instance, gifMeta); } /// @@ -605,12 +602,10 @@ namespace SixLabors.ImageSharp.Formats.Gif } this.metaData = meta; - this.gifMetaData = new GifMetaData - { - ColorTableMode = this.logicalScreenDescriptor.GlobalColorTableFlag - ? GifColorTableMode.Global - : GifColorTableMode.Local - }; + this.gifMetaData = meta.GetFormatMetaData(GifFormat.Instance); + this.gifMetaData.ColorTableMode = this.logicalScreenDescriptor.GlobalColorTableFlag + ? GifColorTableMode.Global + : GifColorTableMode.Local; if (this.logicalScreenDescriptor.GlobalColorTableFlag) { diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index f2e0eab5c2..a516b5fefe 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.gifMetaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + this.gifMetaData = image.MetaData.GetFormatMetaData(GifFormat.Instance); this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; bool useGlobalTable = this.colorTableMode.Equals(GifColorTableMode.Global); @@ -143,7 +143,7 @@ namespace SixLabors.ImageSharp.Formats.Gif for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; - GifFrameMetaData frameMetaData = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData frameMetaData = frame.MetaData.GetFormatMetaData(GifFormat.Instance); this.WriteGraphicalControlExtension(frameMetaData, transparencyIndex, stream); this.WriteImageDescriptor(frame, false, stream); @@ -169,7 +169,7 @@ namespace SixLabors.ImageSharp.Formats.Gif GifFrameMetaData previousMeta = null; foreach (ImageFrame frame in image.Frames) { - GifFrameMetaData meta = frame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData meta = frame.MetaData.GetFormatMetaData(GifFormat.Instance); if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 3daee991c9..7837c2da5c 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -217,8 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { var metaData = new ImageMetaData(); - var pngMetaData = new PngMetaData(); - metaData.AddOrUpdateFormatMetaData(PngFormat.Instance, pngMetaData); + var pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); this.currentStream = stream; this.currentStream.Skip(8); Image image = null; @@ -308,8 +307,7 @@ namespace SixLabors.ImageSharp.Formats.Png public IImageInfo Identify(Stream stream) { var metaData = new ImageMetaData(); - var pngMetaData = new PngMetaData(); - metaData.AddOrUpdateFormatMetaData(PngFormat.Instance, pngMetaData); + var pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); this.currentStream = stream; this.currentStream.Skip(8); try diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 20fc8b8e36..906e6d0003 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -181,7 +181,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.height = image.Height; // Always take the encoder options over the metadata values. - PngMetaData pngMetaData = image.MetaData.GetOrAddFormatMetaData(PngFormat.Instance); + PngMetaData pngMetaData = image.MetaData.GetFormatMetaData(PngFormat.Instance); this.gamma = this.gamma ?? pngMetaData.Gamma; this.writeGamma = this.gamma > 0; this.pngColorType = this.pngColorType ?? pngMetaData.ColorType; diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 908a0e6246..4b819e2013 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -44,27 +44,6 @@ namespace SixLabors.ImageSharp.MetaData /// The cloned instance. public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); - /// - /// Adds or updates the specified key and value to the . - /// - /// The type of format metadata. - /// The type of format frame metadata. - /// The key of the metadata to add. - /// The value of the element to add. - /// key is null. - /// value is null. - /// An element with the same key already exists in the . - public void AddOrUpdateFormatMetaData( - IImageFormat key, - TFormatFrameMetaData value) - where TFormatMetaData : class - where TFormatFrameMetaData : class - { - // Don't think this needs to be threadsafe. - Guard.NotNull(value, nameof(value)); - this.formatMetaData[key] = value; - } - /// /// Gets the metadata value associated with the specified key. /// @@ -74,7 +53,7 @@ namespace SixLabors.ImageSharp.MetaData /// /// The . /// - public TFormatFrameMetaData GetOrAddFormatMetaData(IImageFormat key) + public TFormatFrameMetaData GetFormatMetaData(IImageFormat key) where TFormatMetaData : class where TFormatFrameMetaData : class { @@ -84,7 +63,7 @@ namespace SixLabors.ImageSharp.MetaData } TFormatFrameMetaData newMeta = key.CreateDefaultFormatFrameMetaData(); - this.AddOrUpdateFormatMetaData(key, newMeta); + this.formatMetaData[key] = newMeta; return newMeta; } } diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 74c00cf8a5..7e74157e70 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -131,23 +131,6 @@ namespace SixLabors.ImageSharp.MetaData /// public IList Properties { get; } = new List(); - /// - /// Adds or updates the specified key and value to the . - /// - /// The type of format metadata. - /// The key of the metadata to add. - /// The value of the element to add. - /// key is null. - /// value is null. - /// An element with the same key already exists in the . - public void AddOrUpdateFormatMetaData(IImageFormat key, TFormatMetaData value) - where TFormatMetaData : class - { - // Don't think this needs to be threadsafe. - Guard.NotNull(value, nameof(value)); - this.formatMetaData[key] = value; - } - /// /// Gets the metadata value associated with the specified key. /// @@ -156,7 +139,7 @@ namespace SixLabors.ImageSharp.MetaData /// /// The . /// - public TFormatMetaData GetOrAddFormatMetaData(IImageFormat key) + public TFormatMetaData GetFormatMetaData(IImageFormat key) where TFormatMetaData : class { if (this.formatMetaData.TryGetValue(key, out object meta)) @@ -165,7 +148,7 @@ namespace SixLabors.ImageSharp.MetaData } TFormatMetaData newMeta = key.CreateDefaultFormatMetaData(); - this.AddOrUpdateFormatMetaData(key, newMeta); + this.formatMetaData[key] = newMeta; return newMeta; } diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs index 311b28f2d5..b9f855cf12 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpEncoderTests.cs @@ -80,7 +80,7 @@ namespace SixLabors.ImageSharp.Tests memStream.Position = 0; using (var output = Image.Load(memStream)) { - BmpMetaData meta = output.MetaData.GetOrAddFormatMetaData(BmpFormat.Instance); + BmpMetaData meta = output.MetaData.GetFormatMetaData(BmpFormat.Instance); Assert.Equal(bmpBitsPerPixel, meta.BitsPerPixel); } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 0c32689f09..4a17f867f3 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -189,8 +189,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif inStream.Position = 0; var image = Image.Load(inStream); - GifMetaData metaData = image.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); - GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifMetaData metaData = image.MetaData.GetFormatMetaData(GifFormat.Instance); + GifFrameMetaData frameMetaData = image.Frames.RootFrame.MetaData.GetFormatMetaData(GifFormat.Instance); GifColorTableMode colorMode = metaData.ColorTableMode; var encoder = new GifEncoder() { @@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif outStream.Position = 0; var clone = Image.Load(outStream); - GifMetaData cloneMetaData = clone.MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifMetaData cloneMetaData = clone.MetaData.GetFormatMetaData(GifFormat.Instance); Assert.Equal(metaData.ColorTableMode, cloneMetaData.ColorTableMode); // Gifiddle and Cyotek GifInfo say this image has 64 colors. @@ -212,8 +212,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif for (int i = 0; i < image.Frames.Count; i++) { - GifFrameMetaData ifm = image.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); - GifFrameMetaData cifm = clone.Frames[i].MetaData.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData ifm = image.Frames[i].MetaData.GetFormatMetaData(GifFormat.Instance); + GifFrameMetaData cifm = clone.Frames[i].MetaData.GetFormatMetaData(GifFormat.Instance); Assert.Equal(ifm.ColorTableLength, cifm.ColorTableLength); Assert.Equal(ifm.FrameDelay, cifm.FrameDelay); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index c9435a37dc..0508ac8c26 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -228,7 +228,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png : image; float paletteToleranceHack = 80f / paletteSize; - paletteToleranceHack = paletteToleranceHack * paletteToleranceHack; + paletteToleranceHack *= paletteToleranceHack; ImageComparer comparer = pngColorType == PngColorType.Palette ? ImageComparer.Tolerant(ToleranceThresholdForPaletteEncoder * paletteToleranceHack) : ImageComparer.Exact; @@ -314,7 +314,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png memStream.Position = 0; using (var output = Image.Load(memStream)) { - PngMetaData meta = output.MetaData.GetOrAddFormatMetaData(PngFormat.Instance); + PngMetaData meta = output.MetaData.GetFormatMetaData(PngFormat.Instance); Assert.Equal(pngBitDepth, meta.BitDepth); } diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 54441f0cbf..0a0ca1efa4 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -19,18 +19,14 @@ namespace SixLabors.ImageSharp.Tests const int colorTableLength = 128; const GifDisposalMethod disposalMethod = GifDisposalMethod.RestoreToBackground; - var gifFrameMetaData = new GifFrameMetaData - { - FrameDelay = frameDelay, - ColorTableLength = colorTableLength, - DisposalMethod = disposalMethod - }; - var metaData = new ImageFrameMetaData(); - metaData.AddOrUpdateFormatMetaData(GifFormat.Instance, gifFrameMetaData); + GifFrameMetaData gifFrameMetaData = metaData.GetFormatMetaData(GifFormat.Instance); + gifFrameMetaData.FrameDelay = frameDelay; + gifFrameMetaData.ColorTableLength = colorTableLength; + gifFrameMetaData.DisposalMethod = disposalMethod; var clone = new ImageFrameMetaData(metaData); - GifFrameMetaData cloneGifFrameMetaData = clone.GetOrAddFormatMetaData(GifFormat.Instance); + GifFrameMetaData cloneGifFrameMetaData = clone.GetFormatMetaData(GifFormat.Instance); Assert.Equal(frameDelay, cloneGifFrameMetaData.FrameDelay); Assert.Equal(colorTableLength, cloneGifFrameMetaData.ColorTableLength); From ffc0c7dd19034de9cef1275344397f2eef54b223 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 12 Sep 2018 18:10:06 +0100 Subject: [PATCH 059/185] Can now preserve jpeg quality :heart: --- .../Components/Decoder/QualityEvaluator.cs | 140 ++++++++++++++++++ .../Formats/Jpeg/IJpegEncoderOptions.cs | 7 +- .../Formats/Jpeg/JpegDecoderCore.cs | 14 +- src/ImageSharp/Formats/Jpeg/JpegEncoder.cs | 7 +- .../Formats/Jpeg/JpegEncoderCore.cs | 33 ++--- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 7 +- .../Formats/Jpg/JpegDecoderTests.MetaData.cs | 37 +++++ .../Formats/Jpg/JpegEncoderTests.cs | 72 ++++----- 8 files changed, 232 insertions(+), 85 deletions(-) create mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/QualityEvaluator.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/QualityEvaluator.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/QualityEvaluator.cs new file mode 100644 index 0000000000..4e11568c8d --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/QualityEvaluator.cs @@ -0,0 +1,140 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder +{ + /// + /// Provides methods to evaluate the quality of an image. + /// Ported from + /// + internal static class QualityEvaluator + { + private static readonly int[] Hash = new int[101] + { + 1020, 1015, 932, 848, 780, 735, 702, 679, 660, 645, + 632, 623, 613, 607, 600, 594, 589, 585, 581, 571, + 555, 542, 529, 514, 494, 474, 457, 439, 424, 410, + 397, 386, 373, 364, 351, 341, 334, 324, 317, 309, + 299, 294, 287, 279, 274, 267, 262, 257, 251, 247, + 243, 237, 232, 227, 222, 217, 213, 207, 202, 198, + 192, 188, 183, 177, 173, 168, 163, 157, 153, 148, + 143, 139, 132, 128, 125, 119, 115, 108, 104, 99, + 94, 90, 84, 79, 74, 70, 64, 59, 55, 49, + 45, 40, 34, 30, 25, 20, 15, 11, 6, 4, + 0 + }; + + private static readonly int[] Sums = new int[101] + { + 32640, 32635, 32266, 31495, 30665, 29804, 29146, 28599, 28104, + 27670, 27225, 26725, 26210, 25716, 25240, 24789, 24373, 23946, + 23572, 22846, 21801, 20842, 19949, 19121, 18386, 17651, 16998, + 16349, 15800, 15247, 14783, 14321, 13859, 13535, 13081, 12702, + 12423, 12056, 11779, 11513, 11135, 10955, 10676, 10392, 10208, + 9928, 9747, 9564, 9369, 9193, 9017, 8822, 8639, 8458, + 8270, 8084, 7896, 7710, 7527, 7347, 7156, 6977, 6788, + 6607, 6422, 6236, 6054, 5867, 5684, 5495, 5305, 5128, + 4945, 4751, 4638, 4442, 4248, 4065, 3888, 3698, 3509, + 3326, 3139, 2957, 2775, 2586, 2405, 2216, 2037, 1846, + 1666, 1483, 1297, 1109, 927, 735, 554, 375, 201, + 128, 0 + }; + + private static readonly int[] Hash1 = new int[101] + { + 510, 505, 422, 380, 355, 338, 326, 318, 311, 305, + 300, 297, 293, 291, 288, 286, 284, 283, 281, 280, + 279, 278, 277, 273, 262, 251, 243, 233, 225, 218, + 211, 205, 198, 193, 186, 181, 177, 172, 168, 164, + 158, 156, 152, 148, 145, 142, 139, 136, 133, 131, + 129, 126, 123, 120, 118, 115, 113, 110, 107, 105, + 102, 100, 97, 94, 92, 89, 87, 83, 81, 79, + 76, 74, 70, 68, 66, 63, 61, 57, 55, 52, + 50, 48, 44, 42, 39, 37, 34, 31, 29, 26, + 24, 21, 18, 16, 13, 11, 8, 6, 3, 2, + 0 + }; + + private static readonly int[] Sums1 = new int[101] + { + 16320, 16315, 15946, 15277, 14655, 14073, 13623, 13230, 12859, + 12560, 12240, 11861, 11456, 11081, 10714, 10360, 10027, 9679, + 9368, 9056, 8680, 8331, 7995, 7668, 7376, 7084, 6823, + 6562, 6345, 6125, 5939, 5756, 5571, 5421, 5240, 5086, + 4976, 4829, 4719, 4616, 4463, 4393, 4280, 4166, 4092, + 3980, 3909, 3835, 3755, 3688, 3621, 3541, 3467, 3396, + 3323, 3247, 3170, 3096, 3021, 2952, 2874, 2804, 2727, + 2657, 2583, 2509, 2437, 2362, 2290, 2211, 2136, 2068, + 1996, 1915, 1858, 1773, 1692, 1620, 1552, 1477, 1398, + 1326, 1251, 1179, 1109, 1031, 961, 884, 814, 736, + 667, 592, 518, 441, 369, 292, 221, 151, 86, + 64, 0 + }; + + /// + /// Returns an estimated quality of the image based on the quantization tables. + /// + /// The quantization tables. + /// The . + public static int EstimateQuality(Block8x8F[] quantizationTables) + { + int quality = 75; + float sum = 0; + + for (int i = 0; i < quantizationTables.Length; i++) + { + ref Block8x8F qTable = ref quantizationTables[i]; + for (int j = 0; j < Block8x8F.Size; j++) + { + sum += qTable[j]; + } + } + + ref Block8x8F qTable0 = ref quantizationTables[0]; + ref Block8x8F qTable1 = ref quantizationTables[1]; + + if (!qTable0.Equals(default)) + { + if (!qTable1.Equals(default)) + { + quality = (int)(qTable0[2] + + qTable0[53] + + qTable1[0] + + qTable1[Block8x8F.Size - 1]); + + for (int i = 0; i < 100; i++) + { + if (quality < Hash[i] && sum < Sums[i]) + { + continue; + } + + if (((quality <= Hash[i]) && (sum <= Sums[i])) || (i >= 50)) + { + return i + 1; + } + } + } + else + { + quality = (int)(qTable0[2] + qTable0[53]); + + for (int i = 0; i < 100; i++) + { + if (quality < Hash1[i] && sum < Sums1[i]) + { + continue; + } + + if (((quality <= Hash1[i]) && (sum <= Sums1[i])) || (i >= 50)) + { + return i + 1; + } + } + } + } + + return quality; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs index 4076b7da82..53108de934 100644 --- a/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs +++ b/src/ImageSharp/Formats/Jpeg/IJpegEncoderOptions.cs @@ -8,17 +8,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// internal interface IJpegEncoderOptions { - /// - /// Gets a value indicating whether the metadata should be ignored when the image is being decoded. - /// - bool IgnoreMetadata { get; } - /// /// Gets the quality, that will be used to encode the image. Quality /// index must be between 0 and 100 (compression from max to min). /// /// The quality of the jpg image from 0 to 100. - int Quality { get; } + int? Quality { get; } /// /// Gets the subsample ration, that will be used to encode the image. diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 3ea24809d8..011b6100dc 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -259,11 +259,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.InputStream.Read(this.markerBuffer, 0, 2); byte marker = this.markerBuffer[1]; fileMarker = new JpegFileMarker(marker, (int)this.InputStream.Position - 2); + this.QuantizationTables = new Block8x8F[4]; // Only assign what we need if (!metadataOnly) { - this.QuantizationTables = new Block8x8F[4]; this.dcHuffmanTables = new HuffmanTables(); this.acHuffmanTables = new HuffmanTables(); this.fastACTables = new FastACTables(this.configuration.MemoryAllocator); @@ -314,15 +314,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg break; case JpegConstants.Markers.DQT: - if (metadataOnly) - { - this.InputStream.Skip(remaining); - } - else - { - this.ProcessDefineQuantizationTablesMarker(remaining); - } - + this.ProcessDefineQuantizationTablesMarker(remaining); break; case JpegConstants.Markers.DRI: @@ -708,6 +700,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg { throw new ImageFormatException("DQT has wrong length"); } + + this.MetaData.GetFormatMetaData(JpegFormat.Instance).Quality = QualityEvaluator.EstimateQuality(this.QuantizationTables); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs index 0f389dee0f..d649d30418 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoder.cs @@ -11,17 +11,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// public sealed class JpegEncoder : IImageEncoder, IJpegEncoderOptions { - /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. - /// - public bool IgnoreMetadata { get; set; } - /// /// Gets or sets the quality, that will be used to encode the image. Quality /// index must be between 0 and 100 (compression from max to min). /// Defaults to 75. /// - public int Quality { get; set; } = 75; + public int? Quality { get; set; } /// /// Gets or sets the subsample ration, that will be used to encode the image. diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index f7b6fe9967..32c50d2a08 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -123,19 +123,14 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private readonly byte[] huffmanBuffer = new byte[179]; /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded. + /// Gets or sets the subsampling method to use. /// - private readonly bool ignoreMetadata; + private JpegSubsample? subsample; /// /// The quality, that will be used to encode the image. /// - private readonly int quality; - - /// - /// Gets or sets the subsampling method to use. - /// - private readonly JpegSubsample? subsample; + private readonly int? quality; /// /// The accumulated bits to write to the stream. @@ -168,11 +163,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The options public JpegEncoderCore(IJpegEncoderOptions options) { - // System.Drawing produces identical output for jpegs with a quality parameter of 0 and 1. - this.quality = options.Quality.Clamp(1, 100); - this.subsample = options.Subsample ?? (this.quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); - - this.ignoreMetadata = options.IgnoreMetadata; + this.quality = options.Quality; + this.subsample = options.Subsample; } /// @@ -195,15 +187,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.outputStream = stream; + // System.Drawing produces identical output for jpegs with a quality parameter of 0 and 1. + int qlty = (this.quality ?? image.MetaData.GetFormatMetaData(JpegFormat.Instance).Quality).Clamp(1, 100); + this.subsample = this.subsample ?? (qlty >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); + // Convert from a quality rating to a scaling factor. int scale; - if (this.quality < 50) + if (qlty < 50) { - scale = 5000 / this.quality; + scale = 5000 / qlty; } else { - scale = 200 - (this.quality * 2); + scale = 200 - (qlty * 2); } // Initialize the quantization tables. @@ -767,11 +763,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg private void WriteProfiles(Image image) where TPixel : struct, IPixel { - if (this.ignoreMetadata) - { - return; - } - image.MetaData.SyncProfiles(); this.WriteExifProfile(image.MetaData.ExifProfile); this.WriteIccProfile(image.MetaData.IccProfile); diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs index b05f9fa15a..bd7232e602 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs @@ -8,6 +8,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// public class JpegMetaData { - // TODO: Analyse what properties we would like to preserve. + /// + /// Gets or sets the encoded quality. + /// + public int Quality { get; set; } = 75; } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs index 2e67c06c18..4810985f11 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.MetaData.cs @@ -49,6 +49,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { TestImages.Jpeg.Baseline.GammaDalaiLamaGray, 72, 72, PixelResolutionUnit.PixelsPerInch } }; + public static readonly TheoryData QualityFiles = + new TheoryData + { + { TestImages.Jpeg.Baseline.Calliphora, 80}, + { TestImages.Jpeg.Progressive.Fb, 75 } + }; + [Theory] [MemberData(nameof(MetaDataTestData))] public void MetaDataIsParsedCorrectly( @@ -101,6 +108,36 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } + [Theory] + [MemberData(nameof(QualityFiles))] + public void Identify_VerifyQuality(string imagePath, int quality) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + var decoder = new JpegDecoder(); + IImageInfo image = decoder.Identify(Configuration.Default, stream); + JpegMetaData meta = image.MetaData.GetFormatMetaData(JpegFormat.Instance); + Assert.Equal(quality, meta.Quality); + } + } + + [Theory] + [MemberData(nameof(QualityFiles))] + public void Decode_VerifyQuality(string imagePath, int quality) + { + var testFile = TestFile.Create(imagePath); + using (var stream = new MemoryStream(testFile.Bytes, false)) + { + var decoder = new JpegDecoder(); + using (Image image = decoder.Decode(Configuration.Default, stream)) + { + JpegMetaData meta = image.MetaData.GetFormatMetaData(JpegFormat.Instance); + Assert.Equal(quality, meta.Quality); + } + } + } + private static void TestImageInfo(string imagePath, IImageDecoder decoder, bool useIdentify, Action test) { var testFile = TestFile.Create(imagePath); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index a31ae37b75..598d99274a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -14,6 +14,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { public class JpegEncoderTests { + public static readonly TheoryData QualityFiles = + new TheoryData + { + { TestImages.Jpeg.Baseline.Calliphora, 80}, + { TestImages.Jpeg.Progressive.Fb, 75 } + }; + public static readonly TheoryData BitsPerPixel_Quality = new TheoryData { @@ -34,6 +41,29 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg { TestImages.Jpeg.Baseline.GammaDalaiLamaGray, 72, 72, PixelResolutionUnit.PixelsPerInch } }; + [Theory] + [MemberData(nameof(QualityFiles))] + public void Encode_PreserveQuality(string imagePath, int quality) + { + var options = new JpegEncoder(); + + var testFile = TestFile.Create(imagePath); + using (Image input = testFile.CreateImage()) + { + using (var memStream = new MemoryStream()) + { + input.Save(memStream, options); + + memStream.Position = 0; + using (var output = Image.Load(memStream)) + { + JpegMetaData meta = output.MetaData.GetFormatMetaData(JpegFormat.Instance); + Assert.Equal(quality, meta.Quality); + } + } + } + } + [Theory] [WithFile(TestImages.Png.CalliphoraPartial, nameof(BitsPerPixel_Quality), PixelTypes.Rgba32)] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 73, 71, PixelTypes.Rgba32)] @@ -43,18 +73,12 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg [WithSolidFilledImages(nameof(BitsPerPixel_Quality), 1, 1, 255, 100, 50, 255, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 7, 5, PixelTypes.Rgba32)] public void EncodeBaseline_WorksWithDifferentSizes(TestImageProvider provider, JpegSubsample subsample, int quality) - where TPixel : struct, IPixel - { - TestJpegEncoderCore(provider, subsample, quality); - } + where TPixel : struct, IPixel => TestJpegEncoderCore(provider, subsample, quality); [Theory] [WithTestPatternImages(nameof(BitsPerPixel_Quality), 48, 48, PixelTypes.Rgba32 | PixelTypes.Bgra32)] public void EncodeBaseline_IsNotBoundToSinglePixelType(TestImageProvider provider, JpegSubsample subsample, int quality) - where TPixel : struct, IPixel - { - TestJpegEncoderCore(provider, subsample, quality); - } + where TPixel : struct, IPixel => TestJpegEncoderCore(provider, subsample, quality); /// /// Anton's SUPER-SCIENTIFIC tolerance threshold calculation @@ -103,38 +127,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg } } - [Theory] - [InlineData(false)] - [InlineData(true)] - public void IgnoreMetadata_ControlsIfExifProfileIsWritten(bool ignoreMetaData) - { - var encoder = new JpegEncoder() - { - IgnoreMetadata = ignoreMetaData - }; - - using (Image input = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateImage()) - { - using (var memStream = new MemoryStream()) - { - input.Save(memStream, encoder); - - memStream.Position = 0; - using (var output = Image.Load(memStream)) - { - if (ignoreMetaData) - { - Assert.Null(output.MetaData.ExifProfile); - } - else - { - Assert.NotNull(output.MetaData.ExifProfile); - } - } - } - } - } - [Fact] public void Quality_0_And_1_Are_Identical() { From bce72007971152d848cbdf075e890548c2ad546f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 13 Sep 2018 16:32:58 +0100 Subject: [PATCH 060/185] Make formats public + minor cleanup. --- src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs | 22 +++---- src/ImageSharp/Formats/Bmp/BmpFormat.cs | 2 +- src/ImageSharp/Formats/Gif/GifEncoder.cs | 5 -- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 59 +++++++++---------- src/ImageSharp/Formats/Gif/GifFormat.cs | 2 +- .../Formats/Gif/IGifEncoderOptions.cs | 5 -- .../Formats/Jpeg/JpegEncoderCore.cs | 29 +++++---- src/ImageSharp/Formats/Jpeg/JpegFormat.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoder.cs | 6 -- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 26 ++++---- src/ImageSharp/Formats/Png/PngFormat.cs | 2 +- src/ImageSharp/ImageFrame{TPixel}.cs | 23 ++------ .../Formats/Gif/GifEncoderTests.cs | 16 ++--- 13 files changed, 82 insertions(+), 117 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs index 4ffaf39506..44e42528cf 100644 --- a/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpEncoderCore.cs @@ -48,7 +48,8 @@ namespace SixLabors.ImageSharp.Formats.Bmp Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - BmpMetaData bmpMetaData = image.MetaData.GetFormatMetaData(BmpFormat.Instance); + ImageMetaData metaData = image.MetaData; + BmpMetaData bmpMetaData = metaData.GetFormatMetaData(BmpFormat.Instance); this.bitsPerPixel = this.bitsPerPixel ?? bmpMetaData.BitsPerPixel; short bpp = (short)this.bitsPerPixel; @@ -56,31 +57,30 @@ namespace SixLabors.ImageSharp.Formats.Bmp this.padding = bytesPerLine - (int)(image.Width * (bpp / 8F)); // Set Resolution. - ImageMetaData meta = image.MetaData; int hResolution = 0; int vResolution = 0; - if (meta.ResolutionUnits != PixelResolutionUnit.AspectRatio) + if (metaData.ResolutionUnits != PixelResolutionUnit.AspectRatio) { - if (meta.HorizontalResolution > 0 && meta.VerticalResolution > 0) + if (metaData.HorizontalResolution > 0 && metaData.VerticalResolution > 0) { - switch (meta.ResolutionUnits) + switch (metaData.ResolutionUnits) { case PixelResolutionUnit.PixelsPerInch: - hResolution = (int)Math.Round(UnitConverter.InchToMeter(meta.HorizontalResolution)); - vResolution = (int)Math.Round(UnitConverter.InchToMeter(meta.VerticalResolution)); + hResolution = (int)Math.Round(UnitConverter.InchToMeter(metaData.HorizontalResolution)); + vResolution = (int)Math.Round(UnitConverter.InchToMeter(metaData.VerticalResolution)); break; case PixelResolutionUnit.PixelsPerCentimeter: - hResolution = (int)Math.Round(UnitConverter.CmToMeter(meta.HorizontalResolution)); - vResolution = (int)Math.Round(UnitConverter.CmToMeter(meta.VerticalResolution)); + hResolution = (int)Math.Round(UnitConverter.CmToMeter(metaData.HorizontalResolution)); + vResolution = (int)Math.Round(UnitConverter.CmToMeter(metaData.VerticalResolution)); break; case PixelResolutionUnit.PixelsPerMeter: - hResolution = (int)Math.Round(meta.HorizontalResolution); - vResolution = (int)Math.Round(meta.VerticalResolution); + hResolution = (int)Math.Round(metaData.HorizontalResolution); + vResolution = (int)Math.Round(metaData.VerticalResolution); break; } diff --git a/src/ImageSharp/Formats/Bmp/BmpFormat.cs b/src/ImageSharp/Formats/Bmp/BmpFormat.cs index 665f492daf..a5eaab8ebf 100644 --- a/src/ImageSharp/Formats/Bmp/BmpFormat.cs +++ b/src/ImageSharp/Formats/Bmp/BmpFormat.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Registers the image encoders, decoders and mime type detectors for the bmp format. /// - internal sealed class BmpFormat : IImageFormat + public sealed class BmpFormat : IImageFormat { private BmpFormat() { diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index 9f376044d3..4210b08765 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -14,11 +14,6 @@ namespace SixLabors.ImageSharp.Formats.Gif /// public sealed class GifEncoder : IImageEncoder, IGifEncoderOptions { - /// - /// Gets or sets a value indicating whether the metadata should be ignored when the image is being encoded. - /// - public bool IgnoreMetadata { get; set; } = false; - /// /// Gets or sets the encoding that should be used when writing comments. /// diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index a516b5fefe..ae0366e6e6 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -45,11 +45,6 @@ namespace SixLabors.ImageSharp.Formats.Gif /// private GifColorTableMode? colorTableMode; - /// - /// A flag indicating whether to ingore the metadata when writing the image. - /// - private readonly bool ignoreMetadata; - /// /// The number of bits requires to store the color palette. /// @@ -70,7 +65,6 @@ namespace SixLabors.ImageSharp.Formats.Gif this.memoryAllocator = memoryAllocator; this.textEncoding = options.TextEncoding ?? GifConstants.DefaultEncoding; this.quantizer = options.Quantizer; - this.ignoreMetadata = options.IgnoreMetadata; this.colorTableMode = options.ColorTableMode; } @@ -86,7 +80,8 @@ namespace SixLabors.ImageSharp.Formats.Gif Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - this.gifMetaData = image.MetaData.GetFormatMetaData(GifFormat.Instance); + ImageMetaData metaData = image.MetaData; + this.gifMetaData = metaData.GetFormatMetaData(GifFormat.Instance); this.colorTableMode = this.colorTableMode ?? this.gifMetaData.ColorTableMode; bool useGlobalTable = this.colorTableMode.Equals(GifColorTableMode.Global); @@ -102,7 +97,7 @@ namespace SixLabors.ImageSharp.Formats.Gif // Write the LSD. int index = this.GetTransparentIndex(quantized); - this.WriteLogicalScreenDescriptor(image, index, useGlobalTable, stream); + this.WriteLogicalScreenDescriptor(metaData, image.Width, image.Height, index, useGlobalTable, stream); if (useGlobalTable) { @@ -110,7 +105,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } // Write the comments. - this.WriteComments(image.MetaData, stream); + this.WriteComments(metaData, stream); // Write application extension to allow additional frames. if (image.Frames.Count > 1) @@ -143,7 +138,8 @@ namespace SixLabors.ImageSharp.Formats.Gif for (int i = 0; i < image.Frames.Count; i++) { ImageFrame frame = image.Frames[i]; - GifFrameMetaData frameMetaData = frame.MetaData.GetFormatMetaData(GifFormat.Instance); + ImageFrameMetaData metaData = frame.MetaData; + GifFrameMetaData frameMetaData = metaData.GetFormatMetaData(GifFormat.Instance); this.WriteGraphicalControlExtension(frameMetaData, transparencyIndex, stream); this.WriteImageDescriptor(frame, false, stream); @@ -169,15 +165,16 @@ namespace SixLabors.ImageSharp.Formats.Gif GifFrameMetaData previousMeta = null; foreach (ImageFrame frame in image.Frames) { - GifFrameMetaData meta = frame.MetaData.GetFormatMetaData(GifFormat.Instance); + ImageFrameMetaData metaData = frame.MetaData; + GifFrameMetaData frameMetaData = metaData.GetFormatMetaData(GifFormat.Instance); if (quantized is null) { // Allow each frame to be encoded at whatever color depth the frame designates if set. if (previousFrame != null - && previousMeta.ColorTableLength != meta.ColorTableLength - && meta.ColorTableLength > 0) + && previousMeta.ColorTableLength != frameMetaData.ColorTableLength + && frameMetaData.ColorTableLength > 0) { - quantized = this.quantizer.CreateFrameQuantizer(meta.ColorTableLength).QuantizeFrame(frame); + quantized = this.quantizer.CreateFrameQuantizer(frameMetaData.ColorTableLength).QuantizeFrame(frame); } else { @@ -186,7 +183,7 @@ namespace SixLabors.ImageSharp.Formats.Gif } this.bitDepth = ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); - this.WriteGraphicalControlExtension(meta, this.GetTransparentIndex(quantized), stream); + this.WriteGraphicalControlExtension(frameMetaData, this.GetTransparentIndex(quantized), stream); this.WriteImageDescriptor(frame, true, stream); this.WriteColorTable(quantized, stream); this.WriteImageData(quantized, stream); @@ -194,7 +191,7 @@ namespace SixLabors.ImageSharp.Formats.Gif quantized?.Dispose(); quantized = null; // So next frame can regenerate it previousFrame = frame; - previousMeta = meta; + previousMeta = frameMetaData; } } @@ -239,13 +236,19 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Writes the logical screen descriptor to the stream. /// - /// The pixel format. - /// The image to encode. + /// The image metadata. + /// The image width. + /// The image height. /// The transparency index to set the default background index to. /// Whether to use a global or local color table. /// The stream to write to. - private void WriteLogicalScreenDescriptor(Image image, int transparencyIndex, bool useGlobalTable, Stream stream) - where TPixel : struct, IPixel + private void WriteLogicalScreenDescriptor( + ImageMetaData metaData, + int width, + int height, + int transparencyIndex, + bool useGlobalTable, + Stream stream) { byte packedValue = GifLogicalScreenDescriptor.GetPackedValue(useGlobalTable, this.bitDepth - 1, false, this.bitDepth - 1); @@ -258,13 +261,12 @@ namespace SixLabors.ImageSharp.Formats.Gif // 1..255 - Value used in the computation. // // Aspect Ratio = (Pixel Aspect Ratio + 15) / 64 - ImageMetaData meta = image.MetaData; byte ratio = 0; - if (meta.ResolutionUnits == PixelResolutionUnit.AspectRatio) + if (metaData.ResolutionUnits == PixelResolutionUnit.AspectRatio) { - double hr = meta.HorizontalResolution; - double vr = meta.VerticalResolution; + double hr = metaData.HorizontalResolution; + double vr = metaData.VerticalResolution; if (hr != vr) { if (hr > vr) @@ -279,8 +281,8 @@ namespace SixLabors.ImageSharp.Formats.Gif } var descriptor = new GifLogicalScreenDescriptor( - width: (ushort)image.Width, - height: (ushort)image.Height, + width: (ushort)width, + height: (ushort)height, packed: packedValue, backgroundColorIndex: unchecked((byte)transparencyIndex), ratio); @@ -312,11 +314,6 @@ namespace SixLabors.ImageSharp.Formats.Gif /// The stream to write to. private void WriteComments(ImageMetaData metadata, Stream stream) { - if (this.ignoreMetadata) - { - return; - } - if (!metadata.TryGetProperty(GifConstants.Comments, out ImageProperty property) || string.IsNullOrEmpty(property.Value)) { return; diff --git a/src/ImageSharp/Formats/Gif/GifFormat.cs b/src/ImageSharp/Formats/Gif/GifFormat.cs index f91269ceda..07d4a54547 100644 --- a/src/ImageSharp/Formats/Gif/GifFormat.cs +++ b/src/ImageSharp/Formats/Gif/GifFormat.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Registers the image encoders, decoders and mime type detectors for the gif format. /// - internal sealed class GifFormat : IImageFormat + public sealed class GifFormat : IImageFormat { private GifFormat() { diff --git a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs index 7dd558c803..4b3c28a92c 100644 --- a/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs +++ b/src/ImageSharp/Formats/Gif/IGifEncoderOptions.cs @@ -11,11 +11,6 @@ namespace SixLabors.ImageSharp.Formats.Gif /// internal interface IGifEncoderOptions { - /// - /// Gets a value indicating whether the metadata should be ignored when the image is being encoded. - /// - bool IgnoreMetadata { get; } - /// /// Gets the text encoding used to write comments. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 32c50d2a08..a4677ba2b7 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -186,9 +186,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg } this.outputStream = stream; + ImageMetaData metaData = image.MetaData; // System.Drawing produces identical output for jpegs with a quality parameter of 0 and 1. - int qlty = (this.quality ?? image.MetaData.GetFormatMetaData(JpegFormat.Instance).Quality).Clamp(1, 100); + int qlty = (this.quality ?? metaData.GetFormatMetaData(JpegFormat.Instance).Quality).Clamp(1, 100); this.subsample = this.subsample ?? (qlty >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420); // Convert from a quality rating to a scaling factor. @@ -210,10 +211,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg int componentCount = 3; // Write the Start Of Image marker. - this.WriteApplicationHeader(image.MetaData); + this.WriteApplicationHeader(metaData); // Write Exif and ICC profiles - this.WriteProfiles(image); + this.WriteProfiles(metaData); // Write the quantization tables. this.WriteDefineQuantizationTables(); @@ -620,6 +621,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// private void WriteExifProfile(ExifProfile exifProfile) { + if (exifProfile is null) + { + return; + } + const int MaxBytesApp1 = 65533; const int MaxBytesWithExifId = 65527; @@ -758,14 +764,17 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// Writes the metadata profiles to the image. /// - /// The image. - /// The pixel format. - private void WriteProfiles(Image image) - where TPixel : struct, IPixel + /// The image meta data. + private void WriteProfiles(ImageMetaData metaData) { - image.MetaData.SyncProfiles(); - this.WriteExifProfile(image.MetaData.ExifProfile); - this.WriteIccProfile(image.MetaData.IccProfile); + if (metaData is null) + { + return; + } + + metaData.SyncProfiles(); + this.WriteExifProfile(metaData.ExifProfile); + this.WriteIccProfile(metaData.IccProfile); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs index 94c0895b9d..6b23ceac7a 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegFormat.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegFormat.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// Registers the image encoders, decoders and mime type detectors for the jpeg format. /// - internal sealed class JpegFormat : IImageFormat + public sealed class JpegFormat : IImageFormat { private JpegFormat() { diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index 05d687a888..f47a6518f0 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -51,12 +51,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// public byte Threshold { get; set; } = 255; - /// - /// Gets or sets a value indicating whether this instance should write - /// gamma information to the stream. The default value is false. - /// - public bool WriteGamma { get; set; } - /// /// Encodes the image to the specified stream from the . /// diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 906e6d0003..0b47c1c63e 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -181,7 +181,8 @@ namespace SixLabors.ImageSharp.Formats.Png this.height = image.Height; // Always take the encoder options over the metadata values. - PngMetaData pngMetaData = image.MetaData.GetFormatMetaData(PngFormat.Instance); + ImageMetaData metaData = image.MetaData; + PngMetaData pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); this.gamma = this.gamma ?? pngMetaData.Gamma; this.writeGamma = this.gamma > 0; this.pngColorType = this.pngColorType ?? pngMetaData.ColorType; @@ -245,9 +246,9 @@ namespace SixLabors.ImageSharp.Formats.Png this.WritePaletteChunk(stream, header, quantized); } - this.WritePhysicalChunk(stream, image); + this.WritePhysicalChunk(stream, metaData); this.WriteGammaChunk(stream); - this.WriteExifChunk(stream, image); + this.WriteExifChunk(stream, metaData); this.WriteDataChunks(image.Frames.RootFrame, quantizedPixelsSpan, stream); this.WriteEndChunk(stream); stream.Flush(); @@ -611,11 +612,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Writes the physical dimension information to the stream. /// - /// The pixel format. /// The containing image data. - /// The image. - private void WritePhysicalChunk(Stream stream, Image image) - where TPixel : struct, IPixel + /// The image meta data. + private void WritePhysicalChunk(Stream stream, ImageMetaData meta) { // The pHYs chunk specifies the intended pixel size or aspect ratio for display of the image. It contains: // Pixels per unit, X axis: 4 bytes (unsigned integer) @@ -627,7 +626,6 @@ namespace SixLabors.ImageSharp.Formats.Png // 1: unit is the meter // // When the unit specifier is 0, the pHYs chunk defines pixel aspect ratio only; the actual size of the pixels remains unspecified. - ImageMetaData meta = image.MetaData; Span hResolution = this.chunkDataBuffer.AsSpan(0, 4); Span vResolution = this.chunkDataBuffer.AsSpan(4, 4); @@ -668,16 +666,14 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Writes the eXIf chunk to the stream, if any EXIF Profile values are present in the meta data. /// - /// The pixel format. /// The containing image data. - /// The image. - private void WriteExifChunk(Stream stream, Image image) - where TPixel : struct, IPixel + /// The image meta data. + private void WriteExifChunk(Stream stream, ImageMetaData meta) { - if (image.MetaData.ExifProfile?.Values.Count > 0) + if (meta.ExifProfile?.Values.Count > 0) { - image.MetaData.SyncProfiles(); - this.WriteChunk(stream, PngChunkType.Exif, image.MetaData.ExifProfile.ToByteArray()); + meta.SyncProfiles(); + this.WriteChunk(stream, PngChunkType.Exif, meta.ExifProfile.ToByteArray()); } } diff --git a/src/ImageSharp/Formats/Png/PngFormat.cs b/src/ImageSharp/Formats/Png/PngFormat.cs index b5223cb5a8..210e2a837d 100644 --- a/src/ImageSharp/Formats/Png/PngFormat.cs +++ b/src/ImageSharp/Formats/Png/PngFormat.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Registers the image encoders, decoders and mime type detectors for the png format. /// - internal sealed class PngFormat : IImageFormat + public sealed class PngFormat : IImageFormat { private PngFormat() { diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index a3971fe9ce..132ab598e5 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -84,12 +84,11 @@ namespace SixLabors.ImageSharp Guard.NotNull(configuration, nameof(configuration)); Guard.MustBeGreaterThan(width, 0, nameof(width)); Guard.MustBeGreaterThan(height, 0, nameof(height)); - Guard.NotNull(metaData, nameof(metaData)); this.configuration = configuration; this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(width, height); - this.MetaData = metaData; + this.MetaData = metaData ?? new ImageFrameMetaData(); this.Clear(configuration.GetParallelOptions(), backgroundColor); } @@ -201,10 +200,7 @@ namespace SixLabors.ImageSharp /// The y-coordinate of the pixel. Must be greater than or equal to zero and less than the height of the image. /// The at the specified position. [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal ref TPixel GetPixelReference(int x, int y) - { - return ref this.PixelBuffer[x, y]; - } + internal ref TPixel GetPixelReference(int x, int y) => ref this.PixelBuffer[x, y]; /// /// Copies the pixels to a of the same size. @@ -249,10 +245,7 @@ namespace SixLabors.ImageSharp } /// - public override string ToString() - { - return $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; - } + public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; /// /// Returns a copy of the image frame in the given pixel format. @@ -309,15 +302,9 @@ namespace SixLabors.ImageSharp /// Clones the current instance. /// /// The - internal ImageFrame Clone() - { - return new ImageFrame(this.configuration, this); - } + internal ImageFrame Clone() => new ImageFrame(this.configuration, this); /// - void IDisposable.Dispose() - { - this.Dispose(); - } + void IDisposable.Dispose() => this.Dispose(); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 4a17f867f3..c5c971962c 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -55,10 +55,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif [MemberData(nameof(RatioFiles))] public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { - var options = new GifEncoder() - { - IgnoreMetadata = false - }; + var options = new GifEncoder(); var testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateImage()) @@ -82,10 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif [Fact] public void Encode_IgnoreMetadataIsFalse_CommentsAreWritten() { - var options = new GifEncoder() - { - IgnoreMetadata = false - }; + var options = new GifEncoder(); var testFile = TestFile.Create(TestImages.Gif.Rings); @@ -109,15 +103,13 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif [Fact] public void Encode_IgnoreMetadataIsTrue_CommentsAreNotWritten() { - var options = new GifEncoder() - { - IgnoreMetadata = true - }; + var options = new GifEncoder(); var testFile = TestFile.Create(TestImages.Gif.Rings); using (Image input = testFile.CreateImage()) { + input.MetaData.Properties.Clear(); using (var memStream = new MemoryStream()) { input.SaveAsGif(memStream, options); From 7beff69d4c5b10244a85312b776888b0a12bbac6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 14 Sep 2018 00:16:10 +0200 Subject: [PATCH 061/185] ParallelHelper.IterateRows WIP --- src/ImageSharp/Common/Helpers/ParallelFor.cs | 53 ++++++++++++ src/ImageSharp/Configuration.cs | 21 +++++ src/ImageSharp/Memory/Buffer2DExtensions.cs | 11 ++- .../Helpers/ParallelHelperTests.cs | 83 +++++++++++++++++++ 4 files changed, 162 insertions(+), 6 deletions(-) create mode 100644 tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs diff --git a/src/ImageSharp/Common/Helpers/ParallelFor.cs b/src/ImageSharp/Common/Helpers/ParallelFor.cs index 4c14bb6e3d..7aa50a9e36 100644 --- a/src/ImageSharp/Common/Helpers/ParallelFor.cs +++ b/src/ImageSharp/Common/Helpers/ParallelFor.cs @@ -1,10 +1,63 @@ using System; using System.Buffers; +using System.Runtime.CompilerServices; using System.Threading.Tasks; + +using SixLabors.ImageSharp.Memory; using SixLabors.Memory; +using SixLabors.Primitives; namespace SixLabors.ImageSharp { + internal readonly struct RowInterval + { + public RowInterval(int min, int max) + { + this.Min = min; + this.Max = max; + } + + /// + /// Gets the INCLUSIVE minimum + /// + public int Min { get; } + + /// + /// Gets the EXCLUSIVE maximum + /// + public int Max { get; } + } + + internal static class ParallelHelper + { + public static void IterateRows(in Rectangle rectangle, Configuration configuration, Action body) + { + int maxSteps = (int)Math.Ceiling( + (float)(rectangle.Width * rectangle.Height) / configuration.MinimumPixelsProcessedPerTask); + + int numOfSteps = Math.Min(configuration.MaxDegreeOfParallelism, maxSteps); + + int step = rectangle.Height / numOfSteps; + + var parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = numOfSteps }; + + int bottom = rectangle.Bottom; + + Parallel.For( + 0, + numOfSteps, + parallelOptions, + i => + { + int yMin = i * step; + int yMax = Math.Min(yMin + step, bottom); + + var rowInterval = new RowInterval(yMin, yMax); + body(rowInterval); + }); + } + } + /// /// Utility methods for Parallel.For() execution. Use this instead of raw calls! /// diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 1b009bfedd..4bd6bd9e55 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -29,6 +29,8 @@ namespace SixLabors.ImageSharp private int maxDegreeOfParallelism = Environment.ProcessorCount; + private int minimumPixelsPerTask = 2048; + /// /// Initializes a new instance of the class. /// @@ -59,6 +61,7 @@ namespace SixLabors.ImageSharp /// /// Gets or sets the maximum number of concurrent tasks enabled in ImageSharp algorithms /// configured with this instance. + /// Initialized with by default. /// public int MaxDegreeOfParallelism { @@ -74,6 +77,24 @@ namespace SixLabors.ImageSharp } } + /// + /// Gets or sets the minimum number of pixels being processed by a single task when parallelizing operations with TPL. + /// It's not worth to launch tasks processing pixels below this limit. Initialized with 2048 by default. + /// + public int MinimumPixelsProcessedPerTask + { + get => this.minimumPixelsPerTask; + set + { + if (value <= 0) + { + throw new ArgumentOutOfRangeException(nameof(this.MinimumPixelsProcessedPerTask)); + } + + this.minimumPixelsPerTask = value; + } + } + /// /// Gets the currently registered s. /// diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index 107457ae73..a9edb9cfb6 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -96,15 +96,14 @@ namespace SixLabors.ImageSharp.Memory /// The /// The rectangle subarea /// The - public static BufferArea GetArea(this Buffer2D buffer, Rectangle rectangle) + public static BufferArea GetArea(this Buffer2D buffer, in Rectangle rectangle) where T : struct => new BufferArea(buffer, rectangle); public static BufferArea GetArea(this Buffer2D buffer, int x, int y, int width, int height) - where T : struct - { - var rectangle = new Rectangle(x, y, width, height); - return new BufferArea(buffer, rectangle); - } + where T : struct => new BufferArea(buffer, new Rectangle(x, y, width, height)); + + public static BufferArea GetAreaBetweenRows(this Buffer2D buffer, int minY, int maxY) + where T : struct => new BufferArea(buffer, new Rectangle(0, minY, buffer.Width, maxY - minY)); /// /// Return a to the whole area of 'buffer' diff --git a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs new file mode 100644 index 0000000000..ca904f9539 --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs @@ -0,0 +1,83 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Threading; + +using SixLabors.ImageSharp.Memory; +using SixLabors.Primitives; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Helpers +{ + public class ParallelHelperTests + { + [Theory] + [InlineData(1, 0, 100, -1, 100)] + [InlineData(2, 0, 9, 5, 4)] + [InlineData(2, 10, 19, 5, 4)] + [InlineData(4, 0, 200, 50, 50)] + [InlineData(4, 123, 323, 50, 50)] + public void IterateRows_OverMinimumPixelsLimit( + int maxDegreeOfParallelism, + int minY, + int maxY, + int expectedStep, + int expectedLastStep) + { + Configuration cfg = Configuration.Default.ShallowCopy(); + cfg.MinimumPixelsProcessedPerTask = 1; + cfg.MaxDegreeOfParallelism = maxDegreeOfParallelism; + + var rectangle = new Rectangle(0, minY, 10, maxY); + + int actualNumberOfSteps = 0; + ParallelHelper.IterateRows(rectangle, cfg, + rows => + { + Assert.True(rows.Min >= minY); + int step = rows.Max - rows.Min; + int expected = rows.Max < maxY ? expectedStep : expectedLastStep; + + Interlocked.Increment(ref actualNumberOfSteps); + Assert.Equal(expected, step); + }); + + Assert.Equal(maxDegreeOfParallelism, actualNumberOfSteps); + } + + [Theory] + [InlineData(2, 200, 50, 2, 1, -1, 2)] + [InlineData(2, 200, 200, 1, 1, -1, 1)] + [InlineData(4, 200, 100, 4, 2, 1, 1)] + [InlineData(4, 300, 100, 8, 3, 3, 2)] + public void IterateRows_WithEffectiveMinimumPixelsLimit( + int maxDegreeOfParallelism, + int minimumPixelsProcessedPerTask, + int width, + int height, + int expectedNumberOfSteps, + int expectedStep, + int expectedLastStep) + { + Configuration cfg = Configuration.Default.ShallowCopy(); + cfg.MinimumPixelsProcessedPerTask = minimumPixelsProcessedPerTask; + cfg.MaxDegreeOfParallelism = maxDegreeOfParallelism; + + var rectangle = new Rectangle(0, 0, width, height); + + int actualNumberOfSteps = 0; + ParallelHelper.IterateRows(rectangle, cfg, + rows => + { + int step = rows.Max - rows.Min; + int expected = rows.Max < height ? expectedStep : expectedLastStep; + + Interlocked.Increment(ref actualNumberOfSteps); + Assert.Equal(expected, step); + }); + + Assert.Equal(expectedNumberOfSteps, actualNumberOfSteps); + } + } +} \ No newline at end of file From e65bb17abddc7f15c87b1f706244101c353c0301 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 15 Sep 2018 18:36:38 +0200 Subject: [PATCH 062/185] implemented ParallelHelper.IterateRows() --- src/ImageSharp/Common/Helpers/ParallelFor.cs | 51 ---------- .../ParallelExecutionSettings.cs | 36 +++++++ .../Common/ParallelUtils/ParallelHelper.cs | 95 +++++++++++++++++++ .../Common/ParallelUtils/RowInterval.cs | 35 +++++++ src/ImageSharp/Configuration.cs | 20 ---- src/ImageSharp/ImageSharp.csproj.DotSettings | 3 + .../Helpers/ParallelHelperTests.cs | 42 ++++---- 7 files changed, 193 insertions(+), 89 deletions(-) create mode 100644 src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs create mode 100644 src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs create mode 100644 src/ImageSharp/Common/ParallelUtils/RowInterval.cs create mode 100644 src/ImageSharp/ImageSharp.csproj.DotSettings diff --git a/src/ImageSharp/Common/Helpers/ParallelFor.cs b/src/ImageSharp/Common/Helpers/ParallelFor.cs index 7aa50a9e36..579ae1257e 100644 --- a/src/ImageSharp/Common/Helpers/ParallelFor.cs +++ b/src/ImageSharp/Common/Helpers/ParallelFor.cs @@ -1,63 +1,12 @@ using System; using System.Buffers; -using System.Runtime.CompilerServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Memory; using SixLabors.Memory; -using SixLabors.Primitives; namespace SixLabors.ImageSharp { - internal readonly struct RowInterval - { - public RowInterval(int min, int max) - { - this.Min = min; - this.Max = max; - } - - /// - /// Gets the INCLUSIVE minimum - /// - public int Min { get; } - - /// - /// Gets the EXCLUSIVE maximum - /// - public int Max { get; } - } - - internal static class ParallelHelper - { - public static void IterateRows(in Rectangle rectangle, Configuration configuration, Action body) - { - int maxSteps = (int)Math.Ceiling( - (float)(rectangle.Width * rectangle.Height) / configuration.MinimumPixelsProcessedPerTask); - - int numOfSteps = Math.Min(configuration.MaxDegreeOfParallelism, maxSteps); - - int step = rectangle.Height / numOfSteps; - - var parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = numOfSteps }; - - int bottom = rectangle.Bottom; - - Parallel.For( - 0, - numOfSteps, - parallelOptions, - i => - { - int yMin = i * step; - int yMax = Math.Min(yMin + step, bottom); - - var rowInterval = new RowInterval(yMin, yMax); - body(rowInterval); - }); - } - } - /// /// Utility methods for Parallel.For() execution. Use this instead of raw calls! /// diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs new file mode 100644 index 0000000000..862ea1361c --- /dev/null +++ b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs @@ -0,0 +1,36 @@ +// Copyright(c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Threading.Tasks; + +namespace SixLabors.ImageSharp.ParallelUtils +{ + /// + /// Defines execution settings for methods in . + /// + internal struct ParallelExecutionSettings + { + public ParallelExecutionSettings(int maxDegreeOfParallelism, int minimumPixelsProcessedPerTask) + { + this.MaxDegreeOfParallelism = maxDegreeOfParallelism; + this.MinimumPixelsProcessedPerTask = minimumPixelsProcessedPerTask; + } + + public ParallelExecutionSettings(int maxDegreeOfParallelism) + : this(maxDegreeOfParallelism, 2048) + { + } + + /// + /// Gets the value used for initializing when using TPL. + /// + public int MaxDegreeOfParallelism { get; } + + /// + /// Gets the minimum number of pixels being processed by a single task when parallelizing operations with TPL. + /// Launching tasks for pixel regions below this limit is not worth the overhead. + /// Initialized with 2048 by default, the optimum value is operation specific. + /// + public int MinimumPixelsProcessedPerTask { get; } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs new file mode 100644 index 0000000000..d7cc3b8b13 --- /dev/null +++ b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs @@ -0,0 +1,95 @@ +// Copyright(c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; +using System.Threading.Tasks; + +using SixLabors.ImageSharp.Memory; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.ParallelUtils +{ + /// + /// Utility methods wrapping Parallel.For() execution optimized for image processing. + /// Use this instead of direct calls! + /// + internal static class ParallelHelper + { + /// + /// Get the default for a + /// + public static ParallelExecutionSettings GetParallelSettings(this Configuration configuration) + { + return new ParallelExecutionSettings(configuration.MaxDegreeOfParallelism); + } + + /// + /// Gets a span for all the pixels in defined by + /// + public static Span GetMultiRowSpan(this Buffer2D buffer, in RowInterval rows) + where T : struct + { + return buffer.Span.Slice(rows.Min * buffer.Width, rows.Height * buffer.Width); + } + + /// + /// Iterate through the rows of a rectangle in optimized batches defined by -s. + /// + public static void IterateRows(Rectangle rectangle, Configuration configuration, Action body) + { + ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings(); + + IterateRows(rectangle, parallelSettings, body); + } + + /// + /// Iterate through the rows of a rectangle in optimized batches defined by -s. + /// + public static void IterateRows(Rectangle rectangle, in ParallelExecutionSettings parallelSettings, Action body) + { + int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask); + + int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); + + // Avoid TPL overhead in this trivial case: + if (numOfSteps == 1) + { + var rows = new RowInterval(rectangle.Top, rectangle.Bottom); + body(rows); + return; + } + + int verticalStep = DivideRound(rectangle.Height, numOfSteps); + + var parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = numOfSteps }; + + Parallel.For( + 0, + numOfSteps, + parallelOptions, + i => + { + int yMin = rectangle.Top + (i * verticalStep); + int yMax = Math.Min(yMin + verticalStep, rectangle.Bottom); + + var rowInterval = new RowInterval(yMin, yMax); + body(rowInterval); + }); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int DivideCeil(int dividend, int divisor) + { + // TODO: Is there a more efficient way to calculate this? + int result = dividend / divisor; + return dividend % divisor == 0 ? result : result + 1; + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static int DivideRound(int dividend, int divisor) + { + return (dividend + (divisor / 2)) / divisor; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/ParallelUtils/RowInterval.cs b/src/ImageSharp/Common/ParallelUtils/RowInterval.cs new file mode 100644 index 0000000000..5a30dd7412 --- /dev/null +++ b/src/ImageSharp/Common/ParallelUtils/RowInterval.cs @@ -0,0 +1,35 @@ +// Copyright(c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Memory; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.ParallelUtils +{ + /// + /// Represents an interval of rows in a and/or + /// + internal readonly struct RowInterval + { + public RowInterval(int min, int max) + { + this.Min = min; + this.Max = max; + } + + /// + /// Gets the INCLUSIVE minimum + /// + public int Min { get; } + + /// + /// Gets the EXCLUSIVE maximum + /// + public int Max { get; } + + /// + /// Gets the difference ( - ) + /// + public int Height => this.Max - this.Min; + } +} \ No newline at end of file diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 4bd6bd9e55..c54d02fa30 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -29,8 +29,6 @@ namespace SixLabors.ImageSharp private int maxDegreeOfParallelism = Environment.ProcessorCount; - private int minimumPixelsPerTask = 2048; - /// /// Initializes a new instance of the class. /// @@ -77,24 +75,6 @@ namespace SixLabors.ImageSharp } } - /// - /// Gets or sets the minimum number of pixels being processed by a single task when parallelizing operations with TPL. - /// It's not worth to launch tasks processing pixels below this limit. Initialized with 2048 by default. - /// - public int MinimumPixelsProcessedPerTask - { - get => this.minimumPixelsPerTask; - set - { - if (value <= 0) - { - throw new ArgumentOutOfRangeException(nameof(this.MinimumPixelsProcessedPerTask)); - } - - this.minimumPixelsPerTask = value; - } - } - /// /// Gets the currently registered s. /// diff --git a/src/ImageSharp/ImageSharp.csproj.DotSettings b/src/ImageSharp/ImageSharp.csproj.DotSettings new file mode 100644 index 0000000000..8b2e1bcf07 --- /dev/null +++ b/src/ImageSharp/ImageSharp.csproj.DotSettings @@ -0,0 +1,3 @@ + + True + True \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs index ca904f9539..6c0b570574 100644 --- a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs @@ -3,9 +3,8 @@ using System.Threading; -using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.Primitives; - using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers @@ -15,29 +14,31 @@ namespace SixLabors.ImageSharp.Tests.Helpers [Theory] [InlineData(1, 0, 100, -1, 100)] [InlineData(2, 0, 9, 5, 4)] + [InlineData(4, 0, 19, 5, 4)] [InlineData(2, 10, 19, 5, 4)] [InlineData(4, 0, 200, 50, 50)] [InlineData(4, 123, 323, 50, 50)] + [InlineData(4, 0, 1201, 300, 301)] public void IterateRows_OverMinimumPixelsLimit( int maxDegreeOfParallelism, int minY, int maxY, - int expectedStep, - int expectedLastStep) + int expectedStepLength, + int expectedLastStepLength) { - Configuration cfg = Configuration.Default.ShallowCopy(); - cfg.MinimumPixelsProcessedPerTask = 1; - cfg.MaxDegreeOfParallelism = maxDegreeOfParallelism; + var parallelSettings = new ParallelExecutionSettings(maxDegreeOfParallelism, 1); - var rectangle = new Rectangle(0, minY, 10, maxY); + var rectangle = new Rectangle(0, minY, 10, maxY - minY); int actualNumberOfSteps = 0; - ParallelHelper.IterateRows(rectangle, cfg, + ParallelHelper.IterateRows(rectangle, parallelSettings, rows => { Assert.True(rows.Min >= minY); + Assert.True(rows.Max <= maxY); + int step = rows.Max - rows.Min; - int expected = rows.Max < maxY ? expectedStep : expectedLastStep; + int expected = rows.Max < maxY ? expectedStepLength : expectedLastStepLength; Interlocked.Increment(ref actualNumberOfSteps); Assert.Equal(expected, step); @@ -45,33 +46,38 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(maxDegreeOfParallelism, actualNumberOfSteps); } + [Theory] [InlineData(2, 200, 50, 2, 1, -1, 2)] [InlineData(2, 200, 200, 1, 1, -1, 1)] - [InlineData(4, 200, 100, 4, 2, 1, 1)] + [InlineData(4, 200, 100, 4, 2, 2, 2)] [InlineData(4, 300, 100, 8, 3, 3, 2)] + [InlineData(2, 5000, 1, 4500, 1, -1, 4500)] + [InlineData(2, 5000, 1, 5000, 1, -1, 5000)] + [InlineData(2, 5000, 1, 5001, 2, 2501, 2500)] public void IterateRows_WithEffectiveMinimumPixelsLimit( int maxDegreeOfParallelism, int minimumPixelsProcessedPerTask, int width, int height, int expectedNumberOfSteps, - int expectedStep, - int expectedLastStep) + int expectedStepLength, + int expectedLastStepLength) { - Configuration cfg = Configuration.Default.ShallowCopy(); - cfg.MinimumPixelsProcessedPerTask = minimumPixelsProcessedPerTask; - cfg.MaxDegreeOfParallelism = maxDegreeOfParallelism; + var parallelSettings = new ParallelExecutionSettings(maxDegreeOfParallelism, minimumPixelsProcessedPerTask); var rectangle = new Rectangle(0, 0, width, height); int actualNumberOfSteps = 0; - ParallelHelper.IterateRows(rectangle, cfg, + ParallelHelper.IterateRows(rectangle, parallelSettings, rows => { + Assert.True(rows.Min >= 0); + Assert.True(rows.Max <= height); + int step = rows.Max - rows.Min; - int expected = rows.Max < height ? expectedStep : expectedLastStep; + int expected = rows.Max < height ? expectedStepLength : expectedLastStepLength; Interlocked.Increment(ref actualNumberOfSteps); Assert.Equal(expected, step); From 67334c7d2b5ef59acb684fe34d67f7d3135ccae6 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 15 Sep 2018 19:43:02 +0200 Subject: [PATCH 063/185] implemented IterateRowsWithTempBuffer --- .../ParallelExecutionSettings.cs | 11 +- .../Common/ParallelUtils/ParallelHelper.cs | 72 +++++++-- src/ImageSharp/Memory/Buffer2DExtensions.cs | 9 ++ .../ParallelUtils => Memory}/RowInterval.cs | 5 +- .../Helpers/ParallelHelperTests.cs | 148 +++++++++++++++--- .../Helpers/RowIntervalTests.cs | 38 +++++ 6 files changed, 246 insertions(+), 37 deletions(-) rename src/ImageSharp/{Common/ParallelUtils => Memory}/RowInterval.cs (89%) create mode 100644 tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs index 862ea1361c..89d5fc18d8 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs @@ -3,6 +3,8 @@ using System.Threading.Tasks; +using SixLabors.Memory; + namespace SixLabors.ImageSharp.ParallelUtils { /// @@ -10,17 +12,20 @@ namespace SixLabors.ImageSharp.ParallelUtils /// internal struct ParallelExecutionSettings { - public ParallelExecutionSettings(int maxDegreeOfParallelism, int minimumPixelsProcessedPerTask) + public ParallelExecutionSettings(int maxDegreeOfParallelism, int minimumPixelsProcessedPerTask, MemoryAllocator memoryAllocator) { this.MaxDegreeOfParallelism = maxDegreeOfParallelism; this.MinimumPixelsProcessedPerTask = minimumPixelsProcessedPerTask; + this.MemoryAllocator = memoryAllocator; } - public ParallelExecutionSettings(int maxDegreeOfParallelism) - : this(maxDegreeOfParallelism, 2048) + public ParallelExecutionSettings(int maxDegreeOfParallelism, MemoryAllocator memoryAllocator) + : this(maxDegreeOfParallelism, 2048, memoryAllocator) { } + public MemoryAllocator MemoryAllocator { get; } + /// /// Gets the value used for initializing when using TPL. /// diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs index d7cc3b8b13..a757f50c87 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs @@ -2,10 +2,12 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Runtime.CompilerServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Memory; +using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.ParallelUtils @@ -21,16 +23,7 @@ namespace SixLabors.ImageSharp.ParallelUtils /// public static ParallelExecutionSettings GetParallelSettings(this Configuration configuration) { - return new ParallelExecutionSettings(configuration.MaxDegreeOfParallelism); - } - - /// - /// Gets a span for all the pixels in defined by - /// - public static Span GetMultiRowSpan(this Buffer2D buffer, in RowInterval rows) - where T : struct - { - return buffer.Span.Slice(rows.Min * buffer.Width, rows.Height * buffer.Width); + return new ParallelExecutionSettings(configuration.MaxDegreeOfParallelism, configuration.MemoryAllocator); } /// @@ -46,7 +39,10 @@ namespace SixLabors.ImageSharp.ParallelUtils /// /// Iterate through the rows of a rectangle in optimized batches defined by -s. /// - public static void IterateRows(Rectangle rectangle, in ParallelExecutionSettings parallelSettings, Action body) + public static void IterateRows( + Rectangle rectangle, + in ParallelExecutionSettings parallelSettings, + Action body) { int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask); @@ -73,8 +69,58 @@ namespace SixLabors.ImageSharp.ParallelUtils int yMin = rectangle.Top + (i * verticalStep); int yMax = Math.Min(yMin + verticalStep, rectangle.Bottom); - var rowInterval = new RowInterval(yMin, yMax); - body(rowInterval); + var rows = new RowInterval(yMin, yMax); + body(rows); + }); + } + + /// + /// Iterate through the rows of a rectangle in optimized batches defined by -s + /// instantiating a temporary buffer for each invocation. + /// + public static void IterateRowsWithTempBuffer( + Rectangle rectangle, + in ParallelExecutionSettings parallelSettings, + Action> body) + where T : struct + { + int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask); + + int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); + + MemoryAllocator memoryAllocator = parallelSettings.MemoryAllocator; + + // Avoid TPL overhead in this trivial case: + if (numOfSteps == 1) + { + var rows = new RowInterval(rectangle.Top, rectangle.Bottom); + using (IMemoryOwner buffer = memoryAllocator.Allocate(rectangle.Width)) + { + body(rows, buffer.Memory); + } + + return; + } + + int verticalStep = DivideRound(rectangle.Height, numOfSteps); + + var parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = numOfSteps }; + + Parallel.For( + 0, + numOfSteps, + parallelOptions, + i => + { + int yMin = rectangle.Top + (i * verticalStep); + int yMax = Math.Min(yMin + verticalStep, rectangle.Bottom); + + var rows = new RowInterval(yMin, yMax); + + using (IMemoryOwner buffer = memoryAllocator.Allocate(rectangle.Width)) + { + body(rows, buffer.Memory); + } }); } diff --git a/src/ImageSharp/Memory/Buffer2DExtensions.cs b/src/ImageSharp/Memory/Buffer2DExtensions.cs index a9edb9cfb6..17ab6e2522 100644 --- a/src/ImageSharp/Memory/Buffer2DExtensions.cs +++ b/src/ImageSharp/Memory/Buffer2DExtensions.cs @@ -113,5 +113,14 @@ namespace SixLabors.ImageSharp.Memory /// The public static BufferArea GetArea(this Buffer2D buffer) where T : struct => new BufferArea(buffer); + + /// + /// Gets a span for all the pixels in defined by + /// + public static Span GetMultiRowSpan(this Buffer2D buffer, in RowInterval rows) + where T : struct + { + return buffer.Span.Slice(rows.Min * buffer.Width, rows.Height * buffer.Width); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Common/ParallelUtils/RowInterval.cs b/src/ImageSharp/Memory/RowInterval.cs similarity index 89% rename from src/ImageSharp/Common/ParallelUtils/RowInterval.cs rename to src/ImageSharp/Memory/RowInterval.cs index 5a30dd7412..87b08251b3 100644 --- a/src/ImageSharp/Common/ParallelUtils/RowInterval.cs +++ b/src/ImageSharp/Memory/RowInterval.cs @@ -1,10 +1,9 @@ // Copyright(c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.Memory; using SixLabors.Primitives; -namespace SixLabors.ImageSharp.ParallelUtils +namespace SixLabors.ImageSharp.Memory { /// /// Represents an interval of rows in a and/or @@ -13,6 +12,8 @@ namespace SixLabors.ImageSharp.ParallelUtils { public RowInterval(int min, int max) { + DebugGuard.MustBeLessThan(min, max, nameof(min)); + this.Min = min; this.Max = max; } diff --git a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs index 6c0b570574..35bf1489bb 100644 --- a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs @@ -1,24 +1,39 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Collections.Concurrent; +using System.Linq; +using System.Numerics; using System.Threading; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.Primitives; + using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers { public class ParallelHelperTests { + /// + /// maxDegreeOfParallelism, minY, maxY, expectedStepLength, expectedLastStepLength + /// + public static TheoryData IterateRows_OverMinimumPixelsLimit_Data = + new TheoryData() + { + { 1, 0, 100, -1, 100 }, + { 2, 0, 9, 5, 4 }, + { 4, 0, 19, 5, 4 }, + { 2, 10, 19, 5, 4 }, + { 4, 0, 200, 50, 50 }, + { 4, 123, 323, 50, 50 }, + { 4, 0, 1201, 300, 301 }, + }; + [Theory] - [InlineData(1, 0, 100, -1, 100)] - [InlineData(2, 0, 9, 5, 4)] - [InlineData(4, 0, 19, 5, 4)] - [InlineData(2, 10, 19, 5, 4)] - [InlineData(4, 0, 200, 50, 50)] - [InlineData(4, 123, 323, 50, 50)] - [InlineData(4, 0, 1201, 300, 301)] + [MemberData(nameof(IterateRows_OverMinimumPixelsLimit_Data))] public void IterateRows_OverMinimumPixelsLimit( int maxDegreeOfParallelism, int minY, @@ -26,12 +41,17 @@ namespace SixLabors.ImageSharp.Tests.Helpers int expectedStepLength, int expectedLastStepLength) { - var parallelSettings = new ParallelExecutionSettings(maxDegreeOfParallelism, 1); + var parallelSettings = new ParallelExecutionSettings( + maxDegreeOfParallelism, + 1, + Configuration.Default.MemoryAllocator); var rectangle = new Rectangle(0, minY, 10, maxY - minY); int actualNumberOfSteps = 0; - ParallelHelper.IterateRows(rectangle, parallelSettings, + ParallelHelper.IterateRows( + rectangle, + parallelSettings, rows => { Assert.True(rows.Min >= minY); @@ -46,16 +66,63 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(maxDegreeOfParallelism, actualNumberOfSteps); } - [Theory] - [InlineData(2, 200, 50, 2, 1, -1, 2)] - [InlineData(2, 200, 200, 1, 1, -1, 1)] - [InlineData(4, 200, 100, 4, 2, 2, 2)] - [InlineData(4, 300, 100, 8, 3, 3, 2)] - [InlineData(2, 5000, 1, 4500, 1, -1, 4500)] - [InlineData(2, 5000, 1, 5000, 1, -1, 5000)] - [InlineData(2, 5000, 1, 5001, 2, 2501, 2500)] + [MemberData(nameof(IterateRows_OverMinimumPixelsLimit_Data))] + public void IterateRowsWithTempBuffer_OverMinimumPixelsLimit( + int maxDegreeOfParallelism, + int minY, + int maxY, + int expectedStepLength, + int expectedLastStepLength) + { + var parallelSettings = new ParallelExecutionSettings( + maxDegreeOfParallelism, + 1, + Configuration.Default.MemoryAllocator); + + var rectangle = new Rectangle(0, minY, 10, maxY - minY); + + var bufferHashes = new ConcurrentBag(); + + int actualNumberOfSteps = 0; + ParallelHelper.IterateRowsWithTempBuffer( + rectangle, + parallelSettings, + (RowInterval rows, Memory buffer) => + { + Assert.True(rows.Min >= minY); + Assert.True(rows.Max <= maxY); + + bufferHashes.Add(buffer.GetHashCode()); + + int step = rows.Max - rows.Min; + int expected = rows.Max < maxY ? expectedStepLength : expectedLastStepLength; + + Interlocked.Increment(ref actualNumberOfSteps); + Assert.Equal(expected, step); + }); + + Assert.Equal(maxDegreeOfParallelism, actualNumberOfSteps); + + int numberOfDifferentBuffers = bufferHashes.Distinct().Count(); + Assert.Equal(actualNumberOfSteps, numberOfDifferentBuffers); + } + + public static TheoryData IterateRows_WithEffectiveMinimumPixelsLimit_Data = + new TheoryData() + { + { 2, 200, 50, 2, 1, -1, 2 }, + { 2, 200, 200, 1, 1, -1, 1 }, + { 4, 200, 100, 4, 2, 2, 2 }, + { 4, 300, 100, 8, 3, 3, 2 }, + { 2, 5000, 1, 4500, 1, -1, 4500 }, + { 2, 5000, 1, 5000, 1, -1, 5000 }, + { 2, 5000, 1, 5001, 2, 2501, 2500 }, + }; + + [Theory] + [MemberData(nameof(IterateRows_WithEffectiveMinimumPixelsLimit_Data))] public void IterateRows_WithEffectiveMinimumPixelsLimit( int maxDegreeOfParallelism, int minimumPixelsProcessedPerTask, @@ -65,12 +132,18 @@ namespace SixLabors.ImageSharp.Tests.Helpers int expectedStepLength, int expectedLastStepLength) { - var parallelSettings = new ParallelExecutionSettings(maxDegreeOfParallelism, minimumPixelsProcessedPerTask); + var parallelSettings = new ParallelExecutionSettings( + maxDegreeOfParallelism, + minimumPixelsProcessedPerTask, + Configuration.Default.MemoryAllocator); var rectangle = new Rectangle(0, 0, width, height); int actualNumberOfSteps = 0; - ParallelHelper.IterateRows(rectangle, parallelSettings, + + ParallelHelper.IterateRows( + rectangle, + parallelSettings, rows => { Assert.True(rows.Min >= 0); @@ -85,5 +158,42 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(expectedNumberOfSteps, actualNumberOfSteps); } + + [Theory] + [MemberData(nameof(IterateRows_WithEffectiveMinimumPixelsLimit_Data))] + public void IterateRowsWithTempBuffer_WithEffectiveMinimumPixelsLimit( + int maxDegreeOfParallelism, + int minimumPixelsProcessedPerTask, + int width, + int height, + int expectedNumberOfSteps, + int expectedStepLength, + int expectedLastStepLength) + { + var parallelSettings = new ParallelExecutionSettings( + maxDegreeOfParallelism, + minimumPixelsProcessedPerTask, + Configuration.Default.MemoryAllocator); + + var rectangle = new Rectangle(0, 0, width, height); + + int actualNumberOfSteps = 0; + ParallelHelper.IterateRowsWithTempBuffer( + rectangle, + parallelSettings, + (RowInterval rows, Memory buffer) => + { + Assert.True(rows.Min >= 0); + Assert.True(rows.Max <= height); + + int step = rows.Max - rows.Min; + int expected = rows.Max < height ? expectedStepLength : expectedLastStepLength; + + Interlocked.Increment(ref actualNumberOfSteps); + Assert.Equal(expected, step); + }); + + Assert.Equal(expectedNumberOfSteps, actualNumberOfSteps); + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs new file mode 100644 index 0000000000..f092da7082 --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/RowIntervalTests.cs @@ -0,0 +1,38 @@ +using System; +using System.Runtime.CompilerServices; + +using SixLabors.ImageSharp.Memory; +using SixLabors.Memory; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Helpers +{ + public class RowIntervalTests + { + [Theory] + [InlineData(10, 20, 5, 10)] + [InlineData(1, 10, 0, 10)] + [InlineData(1, 10, 5, 8)] + [InlineData(1, 1, 0, 1)] + [InlineData(10, 20, 9, 10)] + [InlineData(10, 20, 0, 1)] + public void GetMultiRowSpan(int width, int height, int min, int max) + { + using (Buffer2D buffer = Configuration.Default.MemoryAllocator.Allocate2D(width, height)) + { + var rows = new RowInterval(min, max); + + Span span = buffer.GetMultiRowSpan(rows); + + ref int expected0 = ref buffer.Span[min * width]; + int expectedLength = (max - min) * width; + + ref int actual0 = ref span[0]; + + Assert.Equal(span.Length, expectedLength); + Assert.True(Unsafe.AreSame(ref expected0, ref actual0)); + } + } + } +} \ No newline at end of file From 385b3fe68876a927670b88e468cb455cb45baf1a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 17 Sep 2018 23:02:02 +0100 Subject: [PATCH 064/185] Fix png quantization and reduce Wu memory pressure --- .../Common/Extensions/ComparableExtensions.cs | 11 -- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 4 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 19 ++-- .../Quantization/WuFrameQuantizer{TPixel}.cs | 101 +++++++++--------- 4 files changed, 61 insertions(+), 74 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs index d6dade7703..1b0f8ad095 100644 --- a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs +++ b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs @@ -137,17 +137,6 @@ namespace SixLabors.ImageSharp return value; } - /// - /// Converts an to a first restricting the value between the - /// minimum and maximum allowable ranges. - /// - /// The this method extends. - /// The - public static byte ToByte(this int value) - { - return (byte)value.Clamp(0, 255); - } - /// /// Converts an to a first restricting the value between the /// minimum and maximum allowable ranges. diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 7837c2da5c..9281927012 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.Formats.Png where TPixel : struct, IPixel { var metaData = new ImageMetaData(); - var pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); + PngMetaData pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); this.currentStream = stream; this.currentStream.Skip(8); Image image = null; @@ -307,7 +307,7 @@ namespace SixLabors.ImageSharp.Formats.Png public IImageInfo Identify(Stream stream) { var metaData = new ImageMetaData(); - var pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); + PngMetaData pngMetaData = metaData.GetFormatMetaData(PngFormat.Instance); this.currentStream = stream; this.currentStream.Skip(8); try diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 0b47c1c63e..e4d2fc510d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -243,7 +243,7 @@ namespace SixLabors.ImageSharp.Formats.Png // Collect the indexed pixel data if (quantized != null) { - this.WritePaletteChunk(stream, header, quantized); + this.WritePaletteChunk(stream, quantized); } this.WritePhysicalChunk(stream, metaData); @@ -555,30 +555,27 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The pixel format. /// The containing image data. - /// The . /// The quantized frame. - private void WritePaletteChunk(Stream stream, in PngHeader header, QuantizedFrame quantized) + private void WritePaletteChunk(Stream stream, QuantizedFrame quantized) where TPixel : struct, IPixel { // Grab the palette and write it to the stream. TPixel[] palette = quantized.Palette; - byte pixelCount = palette.Length.ToByte(); - - // Get max colors for bit depth. - int colorTableLength = ImageMaths.GetColorCountForBitDepth(header.BitDepth) * 3; + int paletteLength = Math.Min(palette.Length, 256); + int colorTableLength = paletteLength * 3; Rgba32 rgba = default; bool anyAlpha = false; using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) - using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(pixelCount)) + using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(paletteLength)) { Span colorTableSpan = colorTable.GetSpan(); Span alphaTableSpan = alphaTable.GetSpan(); Span quantizedSpan = quantized.GetPixelSpan(); - for (byte i = 0; i < pixelCount; i++) + for (int i = 0; i < paletteLength; i++) { - if (quantizedSpan.IndexOf(i) > -1) + if (quantizedSpan.IndexOf((byte)i) > -1) { int offset = i * 3; palette[i].ToRgba32(ref rgba); @@ -604,7 +601,7 @@ namespace SixLabors.ImageSharp.Formats.Png // Write the transparency data if (anyAlpha) { - this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, pixelCount); + this.WriteChunk(stream, PngChunkType.PaletteAlpha, alphaTable.Array, 0, paletteLength); } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index d71221b9d6..5cd3d53ea2 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -46,12 +46,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The index bits. /// - private const int IndexBits = 6; + private const int IndexBits = 5; /// /// The index alpha bits. /// - private const int IndexAlphaBits = 3; + private const int IndexAlphaBits = 5; /// /// The index count. @@ -201,57 +201,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization return this.palette; } - /// - /// Quantizes the pixel - /// - /// The rgba used to quantize the pixel input - private void QuantizePixel(ref Rgba32 rgba) - { - // Add the color to a 3-D color histogram. - int r = rgba.R >> (8 - IndexBits); - int g = rgba.G >> (8 - IndexBits); - int b = rgba.B >> (8 - IndexBits); - int a = rgba.A >> (8 - IndexAlphaBits); - - int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); - - Span vwtSpan = this.vwt.GetSpan(); - Span vmrSpan = this.vmr.GetSpan(); - Span vmgSpan = this.vmg.GetSpan(); - Span vmbSpan = this.vmb.GetSpan(); - Span vmaSpan = this.vma.GetSpan(); - Span m2Span = this.m2.GetSpan(); - - vwtSpan[index]++; - vmrSpan[index] += rgba.R; - vmgSpan[index] += rgba.G; - vmbSpan[index] += rgba.B; - vmaSpan[index] += rgba.A; - - var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); - m2Span[index] += Vector4.Dot(vector, vector); - } - /// protected override void FirstPass(ImageFrame source, int width, int height) { - // Build up the 3-D color histogram - // Loop through each row - for (int y = 0; y < height; y++) - { - Span row = source.GetPixelRowSpan(y); - ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); - - // And loop through each column - Rgba32 rgba = default; - for (int x = 0; x < width; x++) - { - ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); - pixel.ToRgba32(ref rgba); - this.QuantizePixel(ref rgba); - } - } - + this.Build3DHistogram(source, width, height); this.Get3DMoments(source.MemoryAllocator); this.BuildCube(); } @@ -466,6 +419,54 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization } } + /// + /// Builds a 3-D color histogram of counts, r/g/b, c^2. + /// + /// The source data. + /// The width in pixels of the image. + /// The height in pixels of the image. + private void Build3DHistogram(ImageFrame source, int width, int height) + { + // Build up the 3-D color histogram + // Loop through each row + Span vwtSpan = this.vwt.GetSpan(); + Span vmrSpan = this.vmr.GetSpan(); + Span vmgSpan = this.vmg.GetSpan(); + Span vmbSpan = this.vmb.GetSpan(); + Span vmaSpan = this.vma.GetSpan(); + Span m2Span = this.m2.GetSpan(); + + for (int y = 0; y < height; y++) + { + Span row = source.GetPixelRowSpan(y); + ref TPixel scanBaseRef = ref MemoryMarshal.GetReference(row); + + // And loop through each column + Rgba32 rgba = default; + for (int x = 0; x < width; x++) + { + ref TPixel pixel = ref Unsafe.Add(ref scanBaseRef, x); + pixel.ToRgba32(ref rgba); + + int r = rgba.R >> (8 - IndexBits); + int g = rgba.G >> (8 - IndexBits); + int b = rgba.B >> (8 - IndexBits); + int a = rgba.A >> (8 - IndexAlphaBits); + + int index = GetPaletteIndex(r + 1, g + 1, b + 1, a + 1); + + vwtSpan[index]++; + vmrSpan[index] += rgba.R; + vmgSpan[index] += rgba.G; + vmbSpan[index] += rgba.B; + vmaSpan[index] += rgba.A; + + var vector = new Vector4(rgba.R, rgba.G, rgba.B, rgba.A); + m2Span[index] += Vector4.Dot(vector, vector); + } + } + } + /// /// Converts the histogram into moments so that we can rapidly calculate the sums of the above quantities over any desired box. /// From 6a73c5c1dffe536f03be39f1222b8ec921bcced7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 17 Sep 2018 23:26:59 +0100 Subject: [PATCH 065/185] Minor optimizations to Wu --- .../Quantization/WuFrameQuantizer{TPixel}.cs | 52 ++++++++++++------- 1 file changed, 32 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs index 5cd3d53ea2..13bc057da8 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuFrameQuantizer{TPixel}.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization where TPixel : struct, IPixel { // TODO: The WuFrameQuantizer code is rising several questions: - // - Do we really need to ALWAYS allocate the whole table of size TableLength? (~ 2471625 * sizeof(long) * 5 bytes ) + // - Do we really need to ALWAYS allocate the whole table of size TableLength? (~ 2471625 * sizeof(long) * 5 bytes ) JS. I'm afraid so. // - Isn't an AOS ("array of structures") layout more efficient & more readable than SOA ("structure of arrays") for this particular use case? // (T, R, G, B, A, M2) could be grouped together! // - It's a frequently used class, we need tests! (So we can optimize safely.) There are tests in the original!!! We should just adopt them! @@ -49,7 +49,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private const int IndexBits = 5; /// - /// The index alpha bits. + /// The index alpha bits. Keep separate for now to allow easy adjustment. /// private const int IndexAlphaBits = 5; @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization private const int IndexAlphaCount = (1 << IndexAlphaBits) + 1; /// - /// The table length. + /// The table length. Now 1185921. /// private const int TableLength = IndexCount * IndexCount * IndexCount * IndexAlphaCount; @@ -179,18 +179,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization if (this.palette is null) { this.palette = new TPixel[this.colors]; + Span vwtSpan = this.vwt.GetSpan(); + Span vmrSpan = this.vmr.GetSpan(); + Span vmgSpan = this.vmg.GetSpan(); + Span vmbSpan = this.vmb.GetSpan(); + Span vmaSpan = this.vma.GetSpan(); + for (int k = 0; k < this.colors; k++) { this.Mark(ref this.colorCube[k], (byte)k); - float weight = Volume(ref this.colorCube[k], this.vwt.GetSpan()); + float weight = Volume(ref this.colorCube[k], vwtSpan); if (MathF.Abs(weight) > Constants.Epsilon) { - float r = Volume(ref this.colorCube[k], this.vmr.GetSpan()); - float g = Volume(ref this.colorCube[k], this.vmg.GetSpan()); - float b = Volume(ref this.colorCube[k], this.vmb.GetSpan()); - float a = Volume(ref this.colorCube[k], this.vma.GetSpan()); + float r = Volume(ref this.colorCube[k], vmrSpan); + float g = Volume(ref this.colorCube[k], vmgSpan); + float b = Volume(ref this.colorCube[k], vmbSpan); + float a = Volume(ref this.colorCube[k], vmaSpan); ref TPixel color = ref this.palette[k]; color.PackFromScaledVector4(new Vector4(r, g, b, a) / weight / 255F); @@ -427,8 +433,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The height in pixels of the image. private void Build3DHistogram(ImageFrame source, int width, int height) { - // Build up the 3-D color histogram - // Loop through each row Span vwtSpan = this.vwt.GetSpan(); Span vmrSpan = this.vmr.GetSpan(); Span vmgSpan = this.vmg.GetSpan(); @@ -436,6 +440,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization Span vmaSpan = this.vma.GetSpan(); Span m2Span = this.m2.GetSpan(); + // Build up the 3-D color histogram + // Loop through each row for (int y = 0; y < height; y++) { Span row = source.GetPixelRowSpan(y); @@ -632,22 +638,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The . private float Maximize(ref Box cube, int direction, int first, int last, out int cut, float wholeR, float wholeG, float wholeB, float wholeA, float wholeW) { - long baseR = Bottom(ref cube, direction, this.vmr.GetSpan()); - long baseG = Bottom(ref cube, direction, this.vmg.GetSpan()); - long baseB = Bottom(ref cube, direction, this.vmb.GetSpan()); - long baseA = Bottom(ref cube, direction, this.vma.GetSpan()); - long baseW = Bottom(ref cube, direction, this.vwt.GetSpan()); + Span vwtSpan = this.vwt.GetSpan(); + Span vmrSpan = this.vmr.GetSpan(); + Span vmgSpan = this.vmg.GetSpan(); + Span vmbSpan = this.vmb.GetSpan(); + Span vmaSpan = this.vma.GetSpan(); + + long baseR = Bottom(ref cube, direction, vmrSpan); + long baseG = Bottom(ref cube, direction, vmgSpan); + long baseB = Bottom(ref cube, direction, vmbSpan); + long baseA = Bottom(ref cube, direction, vmaSpan); + long baseW = Bottom(ref cube, direction, vwtSpan); float max = 0F; cut = -1; for (int i = first; i < last; i++) { - float halfR = baseR + Top(ref cube, direction, i, this.vmr.GetSpan()); - float halfG = baseG + Top(ref cube, direction, i, this.vmg.GetSpan()); - float halfB = baseB + Top(ref cube, direction, i, this.vmb.GetSpan()); - float halfA = baseA + Top(ref cube, direction, i, this.vma.GetSpan()); - float halfW = baseW + Top(ref cube, direction, i, this.vwt.GetSpan()); + float halfR = baseR + Top(ref cube, direction, i, vmrSpan); + float halfG = baseG + Top(ref cube, direction, i, vmgSpan); + float halfB = baseB + Top(ref cube, direction, i, vmbSpan); + float halfA = baseA + Top(ref cube, direction, i, vmaSpan); + float halfW = baseW + Top(ref cube, direction, i, vwtSpan); if (MathF.Abs(halfW) < Constants.Epsilon) { From 51e20ec788c5c7b42cfdab111b259c2e6e2124a9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 18 Sep 2018 21:04:46 +0100 Subject: [PATCH 066/185] Begin ToString() formatting. --- src/ImageSharp/ColorSpaces/CieLab.cs | 5 +- src/ImageSharp/ColorSpaces/CieLch.cs | 10 +-- src/ImageSharp/ColorSpaces/CieLchuv.cs | 5 +- src/ImageSharp/ColorSpaces/CieLuv.cs | 5 +- .../CieXyChromaticityCoordinates.cs | 15 +--- src/ImageSharp/ColorSpaces/CieXyy.cs | 10 +-- src/ImageSharp/ColorSpaces/CieXyz.cs | 16 +--- src/ImageSharp/ColorSpaces/Cmyk.cs | 5 +- .../Conversion/ColorSpaceConverter.CieLuv.cs | 1 - .../Conversion/ColorSpaceConverter.CieXyy.cs | 5 +- .../Conversion/ColorSpaceConverter.Cmyk.cs | 5 +- .../Conversion/ColorSpaceConverter.Hsl.cs | 5 +- .../Conversion/ColorSpaceConverter.Hsv.cs | 5 +- .../Conversion/ColorSpaceConverter.Lms.cs | 5 +- .../Conversion/ColorSpaceConverter.YCbCr.cs | 5 +- .../Conversion/VonKriesChromaticAdaptation.cs | 5 +- src/ImageSharp/ColorSpaces/Hsl.cs | 5 +- src/ImageSharp/ColorSpaces/Hsv.cs | 8 +- src/ImageSharp/ColorSpaces/HunterLab.cs | 6 +- src/ImageSharp/ColorSpaces/LinearRgb.cs | 5 +- src/ImageSharp/ColorSpaces/Lms.cs | 5 +- src/ImageSharp/ColorSpaces/Rgb.cs | 15 +--- src/ImageSharp/ColorSpaces/YCbCr.cs | 5 +- src/ImageSharp/PixelFormats/Rgba32.cs | 90 ++++--------------- .../Conversion/StringRepresentationTests.cs | 65 ++++++++++++++ .../Formats/GeneralFormatTests.cs | 16 ++-- tests/Images/Input/Png/splash.png | 4 +- 27 files changed, 123 insertions(+), 208 deletions(-) create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/StringRepresentationTests.cs diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 5ab133cf90..844387b3e1 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -129,10 +129,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"CieLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; - } + public override string ToString() => $"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"; /// public override bool Equals(object obj) => obj is CieLab other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index d2b3d378df..68fe124a6a 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -105,10 +105,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(CieLch left, CieLch right) - { - return left.Equals(right); - } + public static bool operator ==(CieLch left, CieLch right) => left.Equals(right); /// /// Compares two objects for inequality @@ -131,10 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"CieLch [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}]"; - } + public override string ToString() => $"CieLch [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}]"; /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index d46c93c75e..e37f7fa20d 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -127,10 +127,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"CieLchuv [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}"; - } + public override string ToString() => $"CieLchuv [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}"; /// public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index edf865d3c5..10ff7287ed 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -130,10 +130,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]"; - } + public override string ToString() => $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]"; /// public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs index 9b258eda78..64ba44878c 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs @@ -49,10 +49,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right) - { - return left.Equals(right); - } + public static bool operator ==(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right) => left.Equals(right); /// /// Compares two objects for inequality @@ -63,20 +60,14 @@ namespace SixLabors.ImageSharp.ColorSpaces /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right) - { - return !left.Equals(right); - } + public static bool operator !=(CieXyChromaticityCoordinates left, CieXyChromaticityCoordinates right) => !left.Equals(right); /// [MethodImpl(InliningOptions.ShortMethod)] public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode()); /// - public override string ToString() - { - return $"CieXyChromaticityCoordinates [ X={this.X:#0.##}, Y={this.Y:#0.##}]"; - } + public override string ToString() => $"CieXyChromaticityCoordinates [ X={this.X:#0.##}, Y={this.Y:#0.##}]"; /// public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index 831c357027..2b40c30393 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -91,16 +91,10 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"CieXyy [ X={this.X:#0.##}, Y={this.Y:#0.##}, Yl={this.Yl:#0.##} ]"; - } + public override string ToString() => $"CieXyy [ X={this.X:#0.##}, Y={this.Y:#0.##}, Yl={this.Yl:#0.##} ]"; /// - public override bool Equals(object obj) - { - return obj is CieXyy other && this.Equals(other); - } + public override bool Equals(object obj) => obj is CieXyy other && this.Equals(other); /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index a5d409f6b3..b992a7a3e6 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -70,10 +69,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// True if the current left is equal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator ==(CieXyz left, CieXyz right) - { - return left.Equals(right); - } + public static bool operator ==(CieXyz left, CieXyz right) => left.Equals(right); /// /// Compares two objects for inequality. @@ -84,10 +80,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// True if the current left is unequal to the parameter; otherwise, false. /// [MethodImpl(InliningOptions.ShortMethod)] - public static bool operator !=(CieXyz left, CieXyz right) - { - return !left.Equals(right); - } + public static bool operator !=(CieXyz left, CieXyz right) => !left.Equals(right); /// /// Returns a new representing this instance. @@ -105,10 +98,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]"; - } + public override string ToString() => $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]"; /// public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index bc1131aa37..ea3c0b047b 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -96,10 +96,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]"; - } + public override string ToString() => $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]"; /// public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index 5b41ba51e1..b4d9ce08ed 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index b9958af49c..b50f699afb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -152,10 +152,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The color to convert. /// The - public CieXyy ToCieXyy(in CieXyz color) - { - return CieXyzAndCieXyyConverter.Convert(color); - } + public CieXyy ToCieXyy(in CieXyz color) => CieXyzAndCieXyyConverter.Convert(color); /// /// Performs the bulk conversion from into diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index 8aaaad0ae8..bc6c9a949c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -383,10 +383,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The color to convert. /// The - public Cmyk ToCmyk(in Rgb color) - { - return CmykAndRgbConverter.Convert(color); - } + public Cmyk ToCmyk(in Rgb color) => CmykAndRgbConverter.Convert(color); /// /// Performs the bulk conversion from into diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index a91f5a66d1..d88c3a2f23 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -383,10 +383,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The color to convert. /// The - public Hsl ToHsl(in Rgb color) - { - return HslAndRgbConverter.Convert(color); - } + public Hsl ToHsl(in Rgb color) => HslAndRgbConverter.Convert(color); /// /// Performs the bulk conversion from into diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index c03239e164..01ade4375d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -383,10 +383,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The color to convert. /// The - public Hsv ToHsv(in Rgb color) - { - return HsvAndRgbConverter.Convert(color); - } + public Hsv ToHsv(in Rgb color) => HsvAndRgbConverter.Convert(color); /// /// Performs the bulk conversion from into diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index 840a994144..91162cb49b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -177,10 +177,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The color to convert. /// The - public Lms ToLms(in CieXyz color) - { - return this.cieXyzAndLmsConverter.Convert(color); - } + public Lms ToLms(in CieXyz color) => this.cieXyzAndLmsConverter.Convert(color); /// /// Performs the bulk conversion from into diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 2521114fb4..993108c40e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -383,10 +383,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The color to convert. /// The - public YCbCr ToYCbCr(in Rgb color) - { - return YCbCrAndRgbConverter.Convert(color); - } + public YCbCr ToYCbCr(in Rgb color) => YCbCrAndRgbConverter.Convert(color); /// /// Performs the bulk conversion from into diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index 306f013ed3..bc840f7467 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -41,10 +41,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// Initializes a new instance of the class. /// /// The color converter - internal VonKriesChromaticAdaptation(CieXyzAndLmsConverter converter) - { - this.converter = converter; - } + internal VonKriesChromaticAdaptation(CieXyzAndLmsConverter converter) => this.converter = converter; /// public CieXyz Transform(in CieXyz sourceColor, in CieXyz sourceWhitePoint, in CieXyz targetWhitePoint) diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index c6e1e4f9d4..1110241675 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -94,10 +94,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"Hsl [ H={this.H:#0.##}, S={this.S:#0.##}, L={this.L:#0.##} ]"; - } + public override string ToString() => $"Hsl [ H={this.H:#0.##}, S={this.S:#0.##}, L={this.L:#0.##} ]"; /// public override bool Equals(object obj) => obj is Hsl other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index 5fdc287ced..fdd34b1b43 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -2,12 +2,9 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; - namespace SixLabors.ImageSharp.ColorSpaces { /// @@ -95,10 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"Hsv [ H={this.H:#0.##}, S={this.S:#0.##}, V={this.V:#0.##} ]"; - } + public override string ToString() => $"Hsv [ H={this.H:#0.##}, S={this.S:#0.##}, V={this.V:#0.##} ]"; /// public override bool Equals(object obj) => obj is Hsv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index d458fa7895..9c7b456641 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -2,7 +2,6 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.ComponentModel; using System.Numerics; using System.Runtime.CompilerServices; @@ -127,10 +126,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"HunterLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; - } + public override string ToString() => $"HunterLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; /// public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index e7c74cb2dd..d055afc808 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -131,10 +131,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"LinearRgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; - } + public override string ToString() => $"LinearRgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; /// public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 0204a0ebcf..becfea3415 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -97,10 +97,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"Lms [ L={this.L:#0.##}, M={this.M:#0.##}, S={this.S:#0.##} ]"; - } + public override string ToString() => $"Lms [ L={this.L:#0.##}, M={this.M:#0.##}, S={this.S:#0.##} ]"; /// public override bool Equals(object obj) => obj is Lms other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 91a6b23d47..e75de117c0 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -104,10 +104,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The instance of to convert. /// An instance of . [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb(Rgb24 color) - { - return new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); - } + public static implicit operator Rgb(Rgb24 color) => new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); /// /// Allows the implicit conversion of an instance of to a @@ -116,10 +113,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The instance of to convert. /// An instance of . [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb(Rgba32 color) - { - return new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); - } + public static implicit operator Rgb(Rgba32 color) => new Rgb(color.R / 255F, color.G / 255F, color.B / 255F); /// /// Compares two objects for equality. @@ -163,10 +157,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"Rgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; - } + public override string ToString() => $"Rgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; /// public override bool Equals(object obj) => obj is Rgb other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index 0d426f3c24..a1514505a3 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -93,10 +93,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() - { - return $"YCbCr [ Y={this.Y}, Cb={this.Cb}, Cr={this.Cr} ]"; - } + public override string ToString() => $"YCbCr [ Y={this.Y}, Cb={this.Cb}, Cr={this.Cr} ]"; /// public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/Rgba32.cs b/src/ImageSharp/PixelFormats/Rgba32.cs index 623c58d08b..7349639fdc 100644 --- a/src/ImageSharp/PixelFormats/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/Rgba32.cs @@ -111,10 +111,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// The alpha component. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(float r, float g, float b, float a = 1) - : this() - { - this.Pack(r, g, b, a); - } + : this() => this.Pack(r, g, b, a); /// /// Initializes a new instance of the struct. @@ -124,10 +121,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(Vector3 vector) - : this() - { - this.Pack(ref vector); - } + : this() => this.Pack(ref vector); /// /// Initializes a new instance of the struct. @@ -137,10 +131,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(Vector4 vector) - : this() - { - this = PackNew(ref vector); - } + : this() => this = PackNew(ref vector); /// /// Initializes a new instance of the struct. @@ -150,10 +141,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(uint packed) - : this() - { - this.Rgba = packed; - } + : this() => this.Rgba = packed; /// /// Gets or sets the packed representation of the Rgba32 struct. @@ -230,10 +218,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator ==(Rgba32 left, Rgba32 right) - { - return left.Rgba == right.Rgba; - } + public static bool operator ==(Rgba32 left, Rgba32 right) => left.Rgba == right.Rgba; /// /// Compares two objects for equality. @@ -244,10 +229,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// True if the parameter is not equal to the parameter; otherwise, false. /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static bool operator !=(Rgba32 left, Rgba32 right) - { - return left.Rgba != right.Rgba; - } + public static bool operator !=(Rgba32 left, Rgba32 right) => left.Rgba != right.Rgba; /// /// Creates a new instance of the struct. @@ -259,20 +241,14 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// The . /// - public static Rgba32 FromHex(string hex) - { - return ColorBuilder.FromHex(hex); - } + public static Rgba32 FromHex(string hex) => ColorBuilder.FromHex(hex); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromRgba32(Rgba32 source) - { - this = source; - } + public void PackFromRgba32(Rgba32 source) => this = source; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -306,17 +282,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24(ref Rgb24 dest) - { - dest = Unsafe.As(ref this); - } + public void ToRgb24(ref Rgb24 dest) => dest = Unsafe.As(ref this); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32(ref Rgba32 dest) - { - dest = this; - } + public void ToRgba32(ref Rgba32 dest) => dest = this; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -349,31 +319,19 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromScaledVector4(Vector4 vector) - { - this.PackFromVector4(vector); - } + public void PackFromScaledVector4(Vector4 vector) => this.PackFromVector4(vector); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToScaledVector4() - { - return this.ToVector4(); - } + public Vector4 ToScaledVector4() => this.ToVector4(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void PackFromVector4(Vector4 vector) - { - this.Pack(ref vector); - } + public void PackFromVector4(Vector4 vector) => this.Pack(ref vector); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - } + public Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; /// /// Gets the value of this struct as . @@ -428,23 +386,14 @@ namespace SixLabors.ImageSharp.PixelFormats public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); /// - public override bool Equals(object obj) - { - return obj is Rgba32 rgba32 && this.Equals(rgba32); - } + public override bool Equals(object obj) => obj is Rgba32 rgba32 && this.Equals(rgba32); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public bool Equals(Rgba32 other) - { - return this.Rgba == other.Rgba; - } + public bool Equals(Rgba32 other) => this.Rgba == other.Rgba; /// - public override string ToString() - { - return $"({this.R},{this.G},{this.B},{this.A})"; - } + public override string ToString() => $"({this.R},{this.G},{this.B},{this.A})"; /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -455,10 +404,7 @@ namespace SixLabors.ImageSharp.PixelFormats /// /// A of values in [0, 255] [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal Vector4 ToByteScaledVector4() - { - return new Vector4(this.R, this.G, this.B, this.A); - } + internal Vector4 ToByteScaledVector4() => new Vector4(this.R, this.G, this.B, this.A); /// /// Packs a into a color returning a new instance as a result. diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/StringRepresentationTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/StringRepresentationTests.cs new file mode 100644 index 0000000000..580e6cb4ec --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/StringRepresentationTests.cs @@ -0,0 +1,65 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + public class StringRepresentationTests + { + private static readonly Vector3 one = new Vector3(1); + private static readonly Vector3 zero = new Vector3(0); + private static readonly Vector3 random = new Vector3(42.4F, 94.5F, 83.4F); + + public static readonly TheoryData TestData = new TheoryData + { + { new CieLab(zero), "CieLab(0,0,0)" }, + { new CieLch(zero), "CieLch(0,0,0)" }, + { new CieLchuv(zero), "CieLchuv(0,0,0)" }, + { new CieLuv(zero), "CieLuv(0,0,0)" }, + { new CieXyz(zero), "CieXyz(0,0,0)" }, + { new CieXyy(zero), "CieXyy(0,0,0)" }, + { new HunterLab(zero), "HunterLab(0,0,0)" }, + { new Lms(zero), "Lms(0,0,0)" }, + { new LinearRgb(zero), "LinearRgb(0,0,0)" }, + { new Rgb(zero), "Rgb(0,0,0)" }, + { new Hsl(zero), "Hsl(0,0,0)" }, + { new Hsv(zero), "Hsv(0,0,0)" }, + { new YCbCr(zero), "YCbCr(0,0,0)" }, + + { new CieLab(one), "CieLab(1,1,1)" }, + { new CieLch(one), "CieLch(1,1,1)" }, + { new CieLchuv(one), "CieLchuv(1,1,1)" }, + { new CieLuv(one), "CieLuv(1,1,1)" }, + { new CieXyz(one), "CieXyz(1,1,1)" }, + { new CieXyy(one), "CieXyy(1,1,1)" }, + { new HunterLab(one), "HunterLab(1,1,1)" }, + { new Lms(one), "Lms(1,1,1)" }, + { new LinearRgb(one), "LinearRgb(1,1,1)" }, + { new Rgb(one), "Rgb(1,1,1)" }, + { new Hsl(one), "Hsl(1,1,1)" }, + { new Hsv(one), "Hsv(1,1,1)" }, + { new YCbCr(one), "YCbCr(1,1,1)" }, + + { new CieLab(random), "CieLab(42.4,94.5,83.4)" }, + { new CieLch(random), "CieLch(42.4,94.5,83.4)" }, + { new CieLchuv(random), "CieLchuv(42.4,94.5,83.4)" }, + { new CieLuv(random), "CieLuv(42.4,94.5,83.4)" }, + { new CieXyz(random), "CieXyz(42.4,94.5,83.4)" }, + { new CieXyy(random), "CieXyy(42.4,94.5,83.4)" }, + { new HunterLab(random), "HunterLab(42.4,94.5,83.4)" }, + { new Lms(random), "Lms(42.4,94.5,83.4)" }, + { new LinearRgb(random), "LinearRgb(1,1,1)" }, // clamping to 1 is expected + { new Rgb(random), "Rgb(1,1,1)" }, // clamping to 1 is expected + { new Hsl(random), "Hsl(42.4,1,1)" }, // clamping to 1 is expected + { new Hsv(random), "Hsv(42.4,1,1)" }, // clamping to 1 is expected + { new YCbCr(random), "YCbCr(42.4,94.5,83.4)" }, + }; + + [Theory] + [MemberData(nameof(TestData))] + public void StringRepresentationsAreCorrect(object color, string text) => Assert.Equal(text, color.ToString()); + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index f8b035ca83..1d21c65fda 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -14,10 +14,9 @@ namespace SixLabors.ImageSharp.Tests { using System; using System.Reflection; - - using SixLabors.Memory; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; + using SixLabors.Memory; public class GeneralFormatTests : FileTestBase { @@ -58,7 +57,8 @@ namespace SixLabors.ImageSharp.Tests { using (Image image = file.CreateImage()) { - image.Save($"{path}/{file.FileName}"); + var encoder = new PngEncoder { Quantizer = new WuQuantizer(KnownDiffusers.JarvisJudiceNinke, 256), ColorType = PngColorType.Palette }; + image.Save($"{path}/{file.FileName}.png", encoder); } } } @@ -135,15 +135,15 @@ namespace SixLabors.ImageSharp.Tests foreach (TestFile file in Files) { byte[] serialized; - using (Image image = Image.Load(file.Bytes, out IImageFormat mimeType)) - using (MemoryStream memoryStream = new MemoryStream()) + using (var image = Image.Load(file.Bytes, out IImageFormat mimeType)) + using (var memoryStream = new MemoryStream()) { image.Save(memoryStream, mimeType); memoryStream.Flush(); serialized = memoryStream.ToArray(); } - using (Image image2 = Image.Load(serialized)) + using (var image2 = Image.Load(serialized)) { image2.Save($"{path}/{file.FileName}"); } @@ -169,14 +169,14 @@ namespace SixLabors.ImageSharp.Tests [InlineData(10, 100, "jpg")] public void CanIdentifyImageLoadedFromBytes(int width, int height, string format) { - using (Image image = Image.LoadPixelData(new Rgba32[width * height], width, height)) + using (var image = Image.LoadPixelData(new Rgba32[width * height], width, height)) { using (var memoryStream = new MemoryStream()) { image.Save(memoryStream, GetEncoder(format)); memoryStream.Position = 0; - var imageInfo = Image.Identify(memoryStream); + IImageInfo imageInfo = Image.Identify(memoryStream); Assert.Equal(imageInfo.Width, width); Assert.Equal(imageInfo.Height, height); diff --git a/tests/Images/Input/Png/splash.png b/tests/Images/Input/Png/splash.png index ca4f86bced..b37ce5b79c 100644 --- a/tests/Images/Input/Png/splash.png +++ b/tests/Images/Input/Png/splash.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4c13422913f1c1910f8dd607236e79b4a5c7053deb8ce1c8be8372eca7465fb -size 245033 +oid sha256:e9091d56d707eea787687cb77fe526a14d1dd09c2e5f1de27deb71c4b13110fe +size 5081 From 16471da37a5101979ad10b8011611f218a466def Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 18 Sep 2018 22:41:19 +0100 Subject: [PATCH 067/185] Ensure frame metadata is a deep copy. --- .../Formats/Gif/GifFrameMetaData.cs | 23 +++++++++++++- src/ImageSharp/IDeepCloneable.cs | 31 +++++++++++++++++++ src/ImageSharp/ImageFrame{TPixel}.cs | 4 +-- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 20 +++++------- .../Transforms/AffineTransformProcessor.cs | 2 +- .../Processors/Transforms/CropProcessor.cs | 2 +- .../ProjectiveTransformProcessor.cs | 2 +- .../Processors/Transforms/ResizeProcessor.cs | 2 +- 8 files changed, 67 insertions(+), 19 deletions(-) create mode 100644 src/ImageSharp/IDeepCloneable.cs diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index cc04d48314..5b4023f0f3 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -6,8 +6,26 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Provides Gif specific metadata information for the image frame. /// - public class GifFrameMetaData + public class GifFrameMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public GifFrameMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + internal GifFrameMetaData(GifFrameMetaData other) + { + this.ColorTableLength = other.ColorTableLength; + this.FrameDelay = other.FrameDelay; + this.DisposalMethod = other.DisposalMethod; + } + /// /// Gets or sets the length of the color table for paletted images. /// If not 0, then this field indicates the maximum number of colors to use when quantizing the @@ -29,5 +47,8 @@ namespace SixLabors.ImageSharp.Formats.Gif /// be treated after being displayed. /// public GifDisposalMethod DisposalMethod { get; set; } + + /// + public IDeepCloneable DeepClone() => new GifFrameMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/IDeepCloneable.cs b/src/ImageSharp/IDeepCloneable.cs new file mode 100644 index 0000000000..a792fc044d --- /dev/null +++ b/src/ImageSharp/IDeepCloneable.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp +{ + /// + /// A generic interface for a deeply cloneable type. + /// + /// The type of object to clone. + public interface IDeepCloneable + where T : class, IDeepCloneable + { + /// + /// Creates a new that is a deep copy of the current instance. + /// + /// The . + T DeepClone(); + } + + /// + /// An interface for objects that can be cloned. This creates a deep copy of the object. + /// + public interface IDeepCloneable + { + /// + /// Creates a new object that is a deep copy of the current instance. + /// + /// The . + IDeepCloneable DeepClone(); + } +} \ No newline at end of file diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 132ab598e5..dfbae817d6 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); - this.MetaData = source.MetaData.Clone(); + this.MetaData = source.MetaData.DeepClone(); } /// @@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp return this.Clone() as ImageFrame; } - var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.Clone()); + var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.DeepClone()); ParallelFor.WithTemporaryBuffer( 0, diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 4b819e2013..f1f884be68 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Collections.Generic; using SixLabors.ImageSharp.Formats; @@ -10,9 +9,9 @@ namespace SixLabors.ImageSharp.MetaData /// /// Encapsulates the metadata of an image frame. /// - public sealed class ImageFrameMetaData + public sealed class ImageFrameMetaData : IDeepCloneable { - private readonly Dictionary formatMetaData = new Dictionary(); + private readonly Dictionary formatMetaData = new Dictionary(); /// /// Initializes a new instance of the class. @@ -32,17 +31,14 @@ namespace SixLabors.ImageSharp.MetaData { DebugGuard.NotNull(other, nameof(other)); - foreach (KeyValuePair meta in other.formatMetaData) + foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value); + this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); } } - /// - /// Clones this ImageFrameMetaData. - /// - /// The cloned instance. - public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); + /// + public ImageFrameMetaData DeepClone() => new ImageFrameMetaData(this); /// /// Gets the metadata value associated with the specified key. @@ -55,9 +51,9 @@ namespace SixLabors.ImageSharp.MetaData /// public TFormatFrameMetaData GetFormatMetaData(IImageFormat key) where TFormatMetaData : class - where TFormatFrameMetaData : class + where TFormatFrameMetaData : class, IDeepCloneable { - if (this.formatMetaData.TryGetValue(key, out object meta)) + if (this.formatMetaData.TryGetValue(key, out IDeepCloneable meta)) { return (TFormatFrameMetaData)meta; } diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 3993ab1a8d..a7cbb0337c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.Clone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 0c52123755..ab1044df36 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.Clone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 042ce2ff6d..680ce679e1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index fd3c34d6c1..c3d7666221 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.Clone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); From eb9e051da0344787fa26023f1d9ee0368fa4d696 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 19 Sep 2018 12:11:54 +0100 Subject: [PATCH 068/185] All metadata now performs a deep clone --- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 20 +++++- .../Formats/Gif/GifFrameMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifMetaData.cs | 23 ++++++- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 18 ++++- src/ImageSharp/Formats/Png/PngMetaData.cs | 23 ++++++- src/ImageSharp/ImageFrameCollection.cs | 4 +- src/ImageSharp/Image{TPixel}.cs | 4 +- src/ImageSharp/MetaData/ImageMetaData.cs | 38 +++++----- .../MetaData/Profiles/Exif/ExifProfile.cs | 27 +++----- .../MetaData/Profiles/Exif/ExifValue.cs | 69 +++++++++---------- .../MetaData/Profiles/ICC/IccProfile.cs | 36 +++++----- .../Transforms/AffineTransformProcessor.cs | 2 +- .../Processors/Transforms/CropProcessor.cs | 2 +- .../ProjectiveTransformProcessor.cs | 2 +- .../Processors/Transforms/ResizeProcessor.cs | 2 +- .../MetaData/ImageMetaDataTests.cs | 2 +- .../Profiles/Exif/ExifProfileTests.cs | 28 ++++---- 17 files changed, 182 insertions(+), 120 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs index 3d678c13e1..8b33e30fa6 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs @@ -6,13 +6,29 @@ namespace SixLabors.ImageSharp.Formats.Bmp /// /// Provides Bmp specific metadata information for the image. /// - public class BmpMetaData + public class BmpMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public BmpMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + private BmpMetaData(BmpMetaData other) => this.BitsPerPixel = other.BitsPerPixel; + /// /// Gets or sets the number of bits per pixel. /// public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; + /// + public IDeepCloneable DeepClone() => new BmpMetaData(this); + // TODO: Colors used once we support encoding palette bmps. } -} +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index 5b4023f0f3..0042c6a108 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Initializes a new instance of the class. /// /// The metadata to create an instance from. - internal GifFrameMetaData(GifFrameMetaData other) + private GifFrameMetaData(GifFrameMetaData other) { this.ColorTableLength = other.ColorTableLength; this.FrameDelay = other.FrameDelay; diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs index f58f5dff3e..bb7fb50518 100644 --- a/src/ImageSharp/Formats/Gif/GifMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -6,8 +6,26 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Provides Gif specific metadata information for the image. /// - public class GifMetaData + public class GifMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public GifMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + private GifMetaData(GifMetaData other) + { + this.RepeatCount = other.RepeatCount; + this.ColorTableMode = other.ColorTableMode; + this.GlobalColorTableLength = other.GlobalColorTableLength; + } + /// /// Gets or sets the number of times any animation is repeated. /// @@ -25,5 +43,8 @@ namespace SixLabors.ImageSharp.Formats.Gif /// Gets or sets the length of the global color table if present. /// public int GlobalColorTableLength { get; set; } + + /// + public IDeepCloneable DeepClone() => new GifMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs index bd7232e602..fcad29e5d0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs @@ -6,11 +6,27 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// /// Provides Jpeg specific metadata information for the image. /// - public class JpegMetaData + public class JpegMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public JpegMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + private JpegMetaData(JpegMetaData other) => this.Quality = other.Quality; + /// /// Gets or sets the encoded quality. /// public int Quality { get; set; } = 75; + + /// + public IDeepCloneable DeepClone() => new JpegMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 1eb3cdad6a..9c76765146 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -6,8 +6,26 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Provides Png specific metadata information for the image. /// - public class PngMetaData + public class PngMetaData : IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + public PngMetaData() + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The metadata to create an instance from. + private PngMetaData(PngMetaData other) + { + this.BitDepth = other.BitDepth; + this.ColorType = other.ColorType; + this.Gamma = other.Gamma; + } + /// /// Gets or sets the number of bits per sample or per palette index (not per pixel). /// Not all values are allowed for all values. @@ -23,5 +41,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// Gets or sets the gamma value for the image. /// public float Gamma { get; set; } + + /// + public IDeepCloneable DeepClone() => new PngMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 59571ce92e..c55d636279 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp this.frames.Remove(frame); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { frame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { frame }); } /// @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp { ImageFrame frame = this[index]; ImageFrame clonedFrame = frame.Clone(); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { clonedFrame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { clonedFrame }); } /// diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 8bc5a40bdc..bdb1447f29 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp public Image Clone() { IEnumerable> clonedFrames = this.frames.Select(x => x.Clone()); - return new Image(this.configuration, this.MetaData.Clone(), clonedFrames); + return new Image(this.configuration, this.MetaData.DeepClone(), clonedFrames); } /// @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp where TPixel2 : struct, IPixel { IEnumerable> clonedFrames = this.frames.Select(x => x.CloneAs()); - var target = new Image(this.configuration, this.MetaData.Clone(), clonedFrames); + var target = new Image(this.configuration, this.MetaData.DeepClone(), clonedFrames); return target; } diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 7e74157e70..73549d98aa 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Collections.Generic; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.MetaData.Profiles.Exif; @@ -12,7 +11,7 @@ namespace SixLabors.ImageSharp.MetaData /// /// Encapsulates the metadata of an image. /// - public sealed class ImageMetaData + public sealed class ImageMetaData : IDeepCloneable { /// /// The default horizontal resolution value (dots per inch) in x direction. @@ -26,7 +25,13 @@ namespace SixLabors.ImageSharp.MetaData /// public const double DefaultVerticalResolution = 96; - private readonly Dictionary formatMetaData = new Dictionary(); + /// + /// The default pixel resolution units. + /// The default value is . + /// + public const PixelResolutionUnit DefaultPixelResolutionUnits = PixelResolutionUnit.PixelsPerInch; + + private readonly Dictionary formatMetaData = new Dictionary(); private double horizontalResolution; private double verticalResolution; @@ -37,6 +42,7 @@ namespace SixLabors.ImageSharp.MetaData { this.horizontalResolution = DefaultHorizontalResolution; this.verticalResolution = DefaultVerticalResolution; + this.ResolutionUnits = DefaultPixelResolutionUnits; } /// @@ -52,9 +58,9 @@ namespace SixLabors.ImageSharp.MetaData this.VerticalResolution = other.VerticalResolution; this.ResolutionUnits = other.ResolutionUnits; - foreach (KeyValuePair meta in other.formatMetaData) + foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value); + this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); } foreach (ImageProperty property in other.Properties) @@ -62,13 +68,8 @@ namespace SixLabors.ImageSharp.MetaData this.Properties.Add(property); } - this.ExifProfile = other.ExifProfile != null - ? new ExifProfile(other.ExifProfile) - : null; - - this.IccProfile = other.IccProfile != null - ? new IccProfile(other.IccProfile) - : null; + this.ExifProfile = other.ExifProfile?.DeepClone(); + this.IccProfile = other.IccProfile?.DeepClone(); } /// @@ -114,7 +115,7 @@ namespace SixLabors.ImageSharp.MetaData /// 02 : Pixels per centimeter /// 03 : Pixels per meter /// - public PixelResolutionUnit ResolutionUnits { get; set; } = PixelResolutionUnit.PixelsPerInch; + public PixelResolutionUnit ResolutionUnits { get; set; } /// /// Gets or sets the Exif profile. @@ -140,9 +141,9 @@ namespace SixLabors.ImageSharp.MetaData /// The . /// public TFormatMetaData GetFormatMetaData(IImageFormat key) - where TFormatMetaData : class + where TFormatMetaData : class, IDeepCloneable { - if (this.formatMetaData.TryGetValue(key, out object meta)) + if (this.formatMetaData.TryGetValue(key, out IDeepCloneable meta)) { return (TFormatMetaData)meta; } @@ -152,11 +153,8 @@ namespace SixLabors.ImageSharp.MetaData return newMeta; } - /// - /// Clones this into a new instance - /// - /// The cloned metadata instance - public ImageMetaData Clone() => new ImageMetaData(this); + /// + public ImageMetaData DeepClone() => new ImageMetaData(this); /// /// Looks up a property with the provided name. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 1dd8857217..b48b146f11 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -12,23 +12,18 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Represents an EXIF profile providing access to the collection of values. /// - public sealed class ExifProfile + public sealed class ExifProfile : IDeepCloneable { /// /// The byte array to read the EXIF profile from. /// - private byte[] data; + private readonly byte[] data; /// /// The collection of EXIF values /// private List values; - /// - /// The list of invalid EXIF tags - /// - private IReadOnlyList invalidTags; - /// /// The thumbnail offset position in the byte stream /// @@ -55,7 +50,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif { this.Parts = ExifParts.All; this.data = data; - this.invalidTags = new List(); + this.InvalidTags = new List(); } /// @@ -63,22 +58,19 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// by making a copy from another EXIF profile. /// /// The other EXIF profile, where the clone should be made from. - /// is null. - public ExifProfile(ExifProfile other) + private ExifProfile(ExifProfile other) { - Guard.NotNull(other, nameof(other)); - this.Parts = other.Parts; this.thumbnailLength = other.thumbnailLength; this.thumbnailOffset = other.thumbnailOffset; - this.invalidTags = new List(other.invalidTags); + this.InvalidTags = new List(other.InvalidTags); if (other.values != null) { this.values = new List(other.Values.Count); foreach (ExifValue value in other.Values) { - this.values.Add(new ExifValue(value)); + this.values.Add(value.DeepClone()); } } @@ -97,7 +89,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Gets the tags that where found but contained an invalid value. /// - public IReadOnlyList InvalidTags => this.invalidTags; + public IReadOnlyList InvalidTags { get; private set; } /// /// Gets the values of this EXIF profile. @@ -249,6 +241,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return writer.GetData(); } + /// + public ExifProfile DeepClone() => new ExifProfile(this); + /// /// Synchronizes the profiles with the specified meta data. /// @@ -294,7 +289,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif this.values = reader.ReadValues(); - this.invalidTags = new List(reader.InvalidTags); + this.InvalidTags = new List(reader.InvalidTags); this.thumbnailOffset = (int)reader.ThumbnailOffset; this.thumbnailLength = (int)reader.ThumbnailLength; } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index e6da9b7d1e..ccacfd0bf9 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -11,15 +11,30 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// Represent the value of the EXIF profile. /// - public sealed class ExifValue : IEquatable + public sealed class ExifValue : IEquatable, IDeepCloneable { + /// + /// Initializes a new instance of the class. + /// + /// The tag. + /// The data type. + /// The value. + /// Whether the value is an array. + internal ExifValue(ExifTag tag, ExifDataType dataType, object value, bool isArray) + { + this.Tag = tag; + this.DataType = dataType; + this.IsArray = isArray && dataType != ExifDataType.Ascii; + this.Value = value; + } + /// /// Initializes a new instance of the class /// by making a copy from another exif value. /// /// The other exif value, where the clone should be made from. - /// is null. - public ExifValue(ExifValue other) + /// is null. + private ExifValue(ExifValue other) { Guard.NotNull(other, nameof(other)); @@ -29,30 +44,17 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif if (!other.IsArray) { + // All types are value types except for string which is immutable so safe to simply assign. this.Value = other.Value; } else { + // All array types are value types so Clone() is sufficient here. var array = (Array)other.Value; this.Value = array.Clone(); } } - /// - /// Initializes a new instance of the class. - /// - /// The tag. - /// The data type. - /// The value. - /// Whether the value is an array. - internal ExifValue(ExifTag tag, ExifDataType dataType, object value, bool isArray) - { - this.Tag = tag; - this.DataType = dataType; - this.IsArray = isArray && dataType != ExifDataType.Ascii; - this.Value = value; - } - /// /// Gets the data type of the exif value. /// @@ -145,10 +147,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// True if the parameter is equal to the parameter; otherwise, false. /// - public static bool operator ==(ExifValue left, ExifValue right) - { - return ReferenceEquals(left, right) || left.Equals(right); - } + public static bool operator ==(ExifValue left, ExifValue right) => ReferenceEquals(left, right) || left.Equals(right); /// /// Compares two objects for equality. @@ -162,16 +161,10 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - public static bool operator !=(ExifValue left, ExifValue right) - { - return !(left == right); - } + public static bool operator !=(ExifValue left, ExifValue right) => !(left == right); /// - public override bool Equals(object obj) - { - return obj is ExifValue other && this.Equals(other); - } + public override bool Equals(object obj) => obj is ExifValue other && this.Equals(other); /// public bool Equals(ExifValue other) @@ -187,9 +180,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } return - this.Tag == other.Tag && - this.DataType == other.DataType && - object.Equals(this.Value, other.Value); + this.Tag == other.Tag + && this.DataType == other.DataType + && object.Equals(this.Value, other.Value); } /// @@ -205,10 +198,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public override int GetHashCode() - { - return this.GetHashCode(this); - } + public override int GetHashCode() => this.GetHashCode(this); /// public override string ToString() @@ -238,6 +228,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif return sb.ToString(); } + /// + public ExifValue DeepClone() => new ExifValue(this); + /// /// Creates a new /// @@ -584,7 +577,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private static ExifValue CreateNumber(ExifTag tag, object value, bool isArray) { Type type = value?.GetType(); - if (type != null && type.IsArray) + if (type?.IsArray == true) { type = type.GetElementType(); } diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index dac56c608e..44990b7ecc 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// /// Represents an ICC profile /// - public sealed class IccProfile + public sealed class IccProfile : IDeepCloneable { /// /// The byte array to read the ICC profile from @@ -42,23 +42,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// Initializes a new instance of the class. /// /// The raw ICC profile data - public IccProfile(byte[] data) - { - this.data = data; - } - - /// - /// Initializes a new instance of the class - /// by making a copy from another ICC profile. - /// - /// The other ICC profile, where the clone should be made from. - /// is null.> - public IccProfile(IccProfile other) - { - Guard.NotNull(other, nameof(other)); - - this.data = other.ToByteArray(); - } + public IccProfile(byte[] data) => this.data = data; /// /// Initializes a new instance of the class. @@ -74,6 +58,19 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc this.entries = new List(entries); } + /// + /// Initializes a new instance of the class + /// by making a copy from another ICC profile. + /// + /// The other ICC profile, where the clone should be made from. + /// is null.> + private IccProfile(IccProfile other) + { + Guard.NotNull(other, nameof(other)); + + this.data = other.ToByteArray(); + } + /// /// Gets or sets the profile header /// @@ -100,6 +97,9 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } } + /// + public IccProfile DeepClone() => new IccProfile(this); + #if !NETSTANDARD1_1 /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index a7cbb0337c..a7e1589259 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index ab1044df36..df1ac32746 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 680ce679e1..15816cb4dd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index c3d7666221..b1c0632c66 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -218,7 +218,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index d681c90ba2..8a6c516618 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.Clone(); + ImageMetaData clone = metaData.DeepClone(); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(4, clone.HorizontalResolution); diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index 3deb382ea6..c10ffb6c8e 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -67,16 +67,16 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ConstructorCopy() { - Assert.Throws(() => { new ExifProfile((ExifProfile)null); }); + Assert.Throws(() => ((ExifProfile)null).DeepClone()); ExifProfile profile = GetExifProfile(); - var clone = new ExifProfile(profile); + ExifProfile clone = profile.DeepClone(); TestProfile(clone); profile.SetValue(ExifTag.ColorSpace, (ushort)2); - clone = new ExifProfile(profile); + clone = profile.DeepClone(); TestProfile(clone); } @@ -234,10 +234,12 @@ namespace SixLabors.ImageSharp.Tests exifProfile.SetValue(ExifTag.XResolution, new Rational(200)); exifProfile.SetValue(ExifTag.YResolution, new Rational(300)); - var metaData = new ImageMetaData(); - metaData.ExifProfile = exifProfile; - metaData.HorizontalResolution = 200; - metaData.VerticalResolution = 300; + var metaData = new ImageMetaData + { + ExifProfile = exifProfile, + HorizontalResolution = 200, + VerticalResolution = 300 + }; metaData.HorizontalResolution = 100; @@ -355,11 +357,11 @@ namespace SixLabors.ImageSharp.Tests // act Image reloadedImage = WriteAndRead(image, imageFormat); - + // assert ExifProfile actual = reloadedImage.MetaData.ExifProfile; Assert.NotNull(actual); - foreach(KeyValuePair expectedProfileValue in TestProfileValues) + foreach (KeyValuePair expectedProfileValue in TestProfileValues) { ExifValue actualProfileValue = actual.GetValue(expectedProfileValue.Key); Assert.NotNull(actualProfileValue); @@ -371,7 +373,7 @@ namespace SixLabors.ImageSharp.Tests public void ProfileToByteArray() { // arrange - byte[] exifBytesWithExifCode = ProfileResolver.ExifMarker.Concat(ExifConstants.LittleEndianByteOrderMarker).ToArray(); + byte[] exifBytesWithExifCode = ProfileResolver.ExifMarker.Concat(ExifConstants.LittleEndianByteOrderMarker).ToArray(); byte[] exifBytesWithoutExifCode = ExifConstants.LittleEndianByteOrderMarker; ExifProfile expectedProfile = CreateExifProfile(); var expectedProfileTags = expectedProfile.Values.Select(x => x.Tag).ToList(); @@ -384,7 +386,7 @@ namespace SixLabors.ImageSharp.Tests Assert.NotNull(actualBytes); Assert.NotEmpty(actualBytes); Assert.Equal(exifBytesWithoutExifCode, actualBytes.Take(exifBytesWithoutExifCode.Length).ToArray()); - foreach(ExifTag expectedProfileTag in expectedProfileTags) + foreach (ExifTag expectedProfileTag in expectedProfileTags) { ExifValue actualProfileValue = actualProfile.GetValue(expectedProfileTag); ExifValue expectedProfileValue = expectedProfile.GetValue(expectedProfileTag); @@ -396,7 +398,7 @@ namespace SixLabors.ImageSharp.Tests { var profile = new ExifProfile(); - foreach(KeyValuePair exifProfileValue in TestProfileValues) + foreach (KeyValuePair exifProfileValue in TestProfileValues) { profile.SetValue(exifProfileValue.Key, exifProfileValue.Value); } @@ -416,7 +418,7 @@ namespace SixLabors.ImageSharp.Tests private static Image WriteAndRead(Image image, TestImageWriteFormat imageFormat) { - switch(imageFormat) + switch (imageFormat) { case TestImageWriteFormat.Jpeg: return WriteAndReadJpeg(image); From bcfece8a2c629e5ddd93f07200b56179c39c75a3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 19 Sep 2018 13:01:53 +0100 Subject: [PATCH 069/185] Add metadata cloning tests --- .../Formats/Bmp/BmpMetaDataTests.cs | 22 +++++++++++++ .../Formats/Gif/GifFrameMetaDataTests.cs | 32 +++++++++++++++++++ .../Formats/Gif/GifMetaDataTests.cs | 32 +++++++++++++++++++ .../Formats/Jpg/JpegMetaDataTests.cs | 22 +++++++++++++ .../Formats/Png/PngMetaDataTests.cs | 31 ++++++++++++++++++ .../MetaData/ImageFrameMetaDataTests.cs | 8 +++++ .../MetaData/ImageMetaDataTests.cs | 32 ++++++++++++++++--- 7 files changed, 175 insertions(+), 4 deletions(-) create mode 100644 tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs create mode 100644 tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs new file mode 100644 index 0000000000..991768a11a --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Bmp; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Bmp +{ + public class BmpMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new BmpMetaData() { BitsPerPixel = BmpBitsPerPixel.Pixel24 }; + var clone = (BmpMetaData)meta.DeepClone(); + + clone.BitsPerPixel = BmpBitsPerPixel.Pixel32; + + Assert.False(meta.BitsPerPixel.Equals(clone.BitsPerPixel)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs new file mode 100644 index 0000000000..a39fc47b40 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Gif; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Gif +{ + public class GifFrameMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new GifFrameMetaData() + { + FrameDelay = 1, + DisposalMethod = GifDisposalMethod.RestoreToBackground, + ColorTableLength = 2 + }; + + var clone = (GifFrameMetaData)meta.DeepClone(); + + clone.FrameDelay = 2; + clone.DisposalMethod = GifDisposalMethod.RestoreToPrevious; + clone.ColorTableLength = 1; + + Assert.False(meta.FrameDelay.Equals(clone.FrameDelay)); + Assert.False(meta.DisposalMethod.Equals(clone.DisposalMethod)); + Assert.False(meta.ColorTableLength.Equals(clone.ColorTableLength)); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs new file mode 100644 index 0000000000..29db32b4ab --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Gif; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Gif +{ + public class GifMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new GifMetaData() + { + RepeatCount = 1, + ColorTableMode = GifColorTableMode.Global, + GlobalColorTableLength = 2 + }; + + var clone = (GifMetaData)meta.DeepClone(); + + clone.RepeatCount = 2; + clone.ColorTableMode = GifColorTableMode.Local; + clone.GlobalColorTableLength = 1; + + Assert.False(meta.RepeatCount.Equals(clone.RepeatCount)); + Assert.False(meta.ColorTableMode.Equals(clone.ColorTableMode)); + Assert.False(meta.GlobalColorTableLength.Equals(clone.GlobalColorTableLength)); + } + } +} diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs new file mode 100644 index 0000000000..431de4be31 --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs @@ -0,0 +1,22 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Jpeg; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Jpg +{ + public class JpegMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new JpegMetaData() { Quality = 50 }; + var clone = (JpegMetaData)meta.DeepClone(); + + clone.Quality = 99; + + Assert.False(meta.Quality.Equals(clone.Quality)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs new file mode 100644 index 0000000000..a21bb9acbe --- /dev/null +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.Formats.Png; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Formats.Png +{ + public class PngMetaDataTests + { + [Fact] + public void CloneIsDeep() + { + var meta = new PngMetaData() + { + BitDepth = PngBitDepth.Bit16, + ColorType = PngColorType.GrayscaleWithAlpha, + Gamma = 2 + }; + var clone = (PngMetaData)meta.DeepClone(); + + clone.BitDepth = PngBitDepth.Bit2; + clone.ColorType = PngColorType.Palette; + clone.Gamma = 1; + + Assert.False(meta.BitDepth.Equals(clone.BitDepth)); + Assert.False(meta.ColorType.Equals(clone.ColorType)); + Assert.False(meta.Gamma.Equals(clone.Gamma)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 0a0ca1efa4..8c49039603 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -32,5 +32,13 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(colorTableLength, cloneGifFrameMetaData.ColorTableLength); Assert.Equal(disposalMethod, cloneGifFrameMetaData.DisposalMethod); } + + [Fact] + public void CloneIsDeep() + { + var metaData = new ImageFrameMetaData(); + ImageFrameMetaData clone = metaData.DeepClone(); + Assert.False(metaData.GetFormatMetaData(GifFormat.Instance).Equals(clone.GetFormatMetaData(GifFormat.Instance))); + } } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index 8a6c516618..b9619cb3f8 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; +using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.MetaData.Profiles.Exif; using SixLabors.ImageSharp.PixelFormats; @@ -37,19 +37,43 @@ namespace SixLabors.ImageSharp.Tests Assert.Equal(imageProperty, clone.Properties[0]); } + [Fact] + public void CloneIsDeep() + { + var metaData = new ImageMetaData(); + + var exifProfile = new ExifProfile(); + var imageProperty = new ImageProperty("name", "value"); + + metaData.ExifProfile = exifProfile; + metaData.HorizontalResolution = 4; + metaData.VerticalResolution = 2; + metaData.Properties.Add(imageProperty); + + ImageMetaData clone = metaData.DeepClone(); + clone.HorizontalResolution = 2; + clone.VerticalResolution = 4; + + Assert.False(metaData.ExifProfile.Equals(clone.ExifProfile)); + Assert.False(metaData.HorizontalResolution.Equals(clone.HorizontalResolution)); + Assert.False(metaData.VerticalResolution.Equals(clone.VerticalResolution)); + Assert.False(metaData.Properties.Equals(clone.Properties)); + Assert.False(metaData.GetFormatMetaData(GifFormat.Instance).Equals(clone.GetFormatMetaData(GifFormat.Instance))); + } + [Fact] public void HorizontalResolution() { var metaData = new ImageMetaData(); Assert.Equal(96, metaData.HorizontalResolution); - metaData.HorizontalResolution=0; + metaData.HorizontalResolution = 0; Assert.Equal(96, metaData.HorizontalResolution); - metaData.HorizontalResolution=-1; + metaData.HorizontalResolution = -1; Assert.Equal(96, metaData.HorizontalResolution); - metaData.HorizontalResolution=1; + metaData.HorizontalResolution = 1; Assert.Equal(1, metaData.HorizontalResolution); } From 251ae936a72f7f789db12abc7a7f0b8d9e9bfaee Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Sep 2018 18:07:11 +0100 Subject: [PATCH 070/185] Rename DeepClone => Clone --- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifFrameMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifMetaData.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 2 +- src/ImageSharp/Formats/Png/PngMetaData.cs | 2 +- src/ImageSharp/IDeepCloneable.cs | 4 ++-- src/ImageSharp/ImageFrameCollection.cs | 4 ++-- src/ImageSharp/ImageFrame{TPixel}.cs | 4 ++-- src/ImageSharp/Image{TPixel}.cs | 4 ++-- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 4 ++-- src/ImageSharp/MetaData/ImageMetaData.cs | 8 ++++---- src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs | 4 ++-- src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs | 2 +- src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs | 2 +- .../Processors/Transforms/AffineTransformProcessor.cs | 4 ++-- .../Processing/Processors/Transforms/CropProcessor.cs | 4 ++-- .../Processors/Transforms/ProjectiveTransformProcessor.cs | 4 ++-- .../Processing/Processors/Transforms/ResizeProcessor.cs | 4 ++-- tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs | 2 +- .../ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs | 2 +- .../ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs | 2 +- tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs | 4 ++-- .../MetaData/Profiles/Exif/ExifProfileTests.cs | 6 +++--- 26 files changed, 42 insertions(+), 42 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs index 8b33e30fa6..134c8904b8 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; /// - public IDeepCloneable DeepClone() => new BmpMetaData(this); + public IDeepCloneable Clone() => new BmpMetaData(this); // TODO: Colors used once we support encoding palette bmps. } diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index 0042c6a108..47af2bbdc0 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -49,6 +49,6 @@ namespace SixLabors.ImageSharp.Formats.Gif public GifDisposalMethod DisposalMethod { get; set; } /// - public IDeepCloneable DeepClone() => new GifFrameMetaData(this); + public IDeepCloneable Clone() => new GifFrameMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs index bb7fb50518..7a91a3a75e 100644 --- a/src/ImageSharp/Formats/Gif/GifMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -45,6 +45,6 @@ namespace SixLabors.ImageSharp.Formats.Gif public int GlobalColorTableLength { get; set; } /// - public IDeepCloneable DeepClone() => new GifMetaData(this); + public IDeepCloneable Clone() => new GifMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs index fcad29e5d0..5cef3355a0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs @@ -27,6 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg public int Quality { get; set; } = 75; /// - public IDeepCloneable DeepClone() => new JpegMetaData(this); + public IDeepCloneable Clone() => new JpegMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index 9c76765146..e9f0dc6c42 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -43,6 +43,6 @@ namespace SixLabors.ImageSharp.Formats.Png public float Gamma { get; set; } /// - public IDeepCloneable DeepClone() => new PngMetaData(this); + public IDeepCloneable Clone() => new PngMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/IDeepCloneable.cs b/src/ImageSharp/IDeepCloneable.cs index a792fc044d..04c60a6252 100644 --- a/src/ImageSharp/IDeepCloneable.cs +++ b/src/ImageSharp/IDeepCloneable.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp /// Creates a new that is a deep copy of the current instance. /// /// The . - T DeepClone(); + T Clone(); } /// @@ -26,6 +26,6 @@ namespace SixLabors.ImageSharp /// Creates a new object that is a deep copy of the current instance. /// /// The . - IDeepCloneable DeepClone(); + IDeepCloneable Clone(); } } \ No newline at end of file diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index c55d636279..59571ce92e 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp this.frames.Remove(frame); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { frame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { frame }); } /// @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp { ImageFrame frame = this[index]; ImageFrame clonedFrame = frame.Clone(); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { clonedFrame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { clonedFrame }); } /// diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index dfbae817d6..132ab598e5 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -135,7 +135,7 @@ namespace SixLabors.ImageSharp this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); - this.MetaData = source.MetaData.DeepClone(); + this.MetaData = source.MetaData.Clone(); } /// @@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp return this.Clone() as ImageFrame; } - var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.DeepClone()); + var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.Clone()); ParallelFor.WithTemporaryBuffer( 0, diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index bdb1447f29..8bc5a40bdc 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -190,7 +190,7 @@ namespace SixLabors.ImageSharp public Image Clone() { IEnumerable> clonedFrames = this.frames.Select(x => x.Clone()); - return new Image(this.configuration, this.MetaData.DeepClone(), clonedFrames); + return new Image(this.configuration, this.MetaData.Clone(), clonedFrames); } /// @@ -208,7 +208,7 @@ namespace SixLabors.ImageSharp where TPixel2 : struct, IPixel { IEnumerable> clonedFrames = this.frames.Select(x => x.CloneAs()); - var target = new Image(this.configuration, this.MetaData.DeepClone(), clonedFrames); + var target = new Image(this.configuration, this.MetaData.Clone(), clonedFrames); return target; } diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index f1f884be68..26c717f2a4 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -33,12 +33,12 @@ namespace SixLabors.ImageSharp.MetaData foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); + this.formatMetaData.Add(meta.Key, meta.Value.Clone()); } } /// - public ImageFrameMetaData DeepClone() => new ImageFrameMetaData(this); + public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); /// /// Gets the metadata value associated with the specified key. diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 73549d98aa..44c1738cf0 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.MetaData foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); + this.formatMetaData.Add(meta.Key, meta.Value.Clone()); } foreach (ImageProperty property in other.Properties) @@ -68,8 +68,8 @@ namespace SixLabors.ImageSharp.MetaData this.Properties.Add(property); } - this.ExifProfile = other.ExifProfile?.DeepClone(); - this.IccProfile = other.IccProfile?.DeepClone(); + this.ExifProfile = other.ExifProfile?.Clone(); + this.IccProfile = other.IccProfile?.Clone(); } /// @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.MetaData } /// - public ImageMetaData DeepClone() => new ImageMetaData(this); + public ImageMetaData Clone() => new ImageMetaData(this); /// /// Looks up a property with the provided name. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index b48b146f11..7b71a78eb9 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif foreach (ExifValue value in other.Values) { - this.values.Add(value.DeepClone()); + this.values.Add(value.Clone()); } } @@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public ExifProfile DeepClone() => new ExifProfile(this); + public ExifProfile Clone() => new ExifProfile(this); /// /// Synchronizes the profiles with the specified meta data. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index ccacfd0bf9..88827820c3 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -229,7 +229,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public ExifValue DeepClone() => new ExifValue(this); + public ExifValue Clone() => new ExifValue(this); /// /// Creates a new diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 44990b7ecc..3885303d45 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } /// - public IccProfile DeepClone() => new IccProfile(this); + public IccProfile Clone() => new IccProfile(this); #if !NETSTANDARD1_1 diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index a7e1589259..3993ab1a8d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -51,10 +51,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.Clone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index df1ac32746..0c52123755 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -36,10 +36,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.DeepClone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.Clone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 15816cb4dd..042ce2ff6d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -51,10 +51,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.DeepClone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index b1c0632c66..fd3c34d6c1 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -215,10 +215,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.DeepClone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.Clone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); } /// diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs index 991768a11a..ca36a1eb5f 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp public void CloneIsDeep() { var meta = new BmpMetaData() { BitsPerPixel = BmpBitsPerPixel.Pixel24 }; - var clone = (BmpMetaData)meta.DeepClone(); + var clone = (BmpMetaData)meta.Clone(); clone.BitsPerPixel = BmpBitsPerPixel.Pixel32; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs index a39fc47b40..4879a56739 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif ColorTableLength = 2 }; - var clone = (GifFrameMetaData)meta.DeepClone(); + var clone = (GifFrameMetaData)meta.Clone(); clone.FrameDelay = 2; clone.DisposalMethod = GifDisposalMethod.RestoreToPrevious; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs index 29db32b4ab..4f42753164 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif GlobalColorTableLength = 2 }; - var clone = (GifMetaData)meta.DeepClone(); + var clone = (GifMetaData)meta.Clone(); clone.RepeatCount = 2; clone.ColorTableMode = GifColorTableMode.Local; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs index 431de4be31..054e79f514 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void CloneIsDeep() { var meta = new JpegMetaData() { Quality = 50 }; - var clone = (JpegMetaData)meta.DeepClone(); + var clone = (JpegMetaData)meta.Clone(); clone.Quality = 99; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs index a21bb9acbe..4b209613ae 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png ColorType = PngColorType.GrayscaleWithAlpha, Gamma = 2 }; - var clone = (PngMetaData)meta.DeepClone(); + var clone = (PngMetaData)meta.Clone(); clone.BitDepth = PngBitDepth.Bit2; clone.ColorType = PngColorType.Palette; diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 8c49039603..428b7c431a 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests public void CloneIsDeep() { var metaData = new ImageFrameMetaData(); - ImageFrameMetaData clone = metaData.DeepClone(); + ImageFrameMetaData clone = metaData.Clone(); Assert.False(metaData.GetFormatMetaData(GifFormat.Instance).Equals(clone.GetFormatMetaData(GifFormat.Instance))); } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index b9619cb3f8..79fd7b7d2b 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.DeepClone(); + ImageMetaData clone = metaData.Clone(); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(4, clone.HorizontalResolution); @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.DeepClone(); + ImageMetaData clone = metaData.Clone(); clone.HorizontalResolution = 2; clone.VerticalResolution = 4; diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index c10ffb6c8e..ee41c1759f 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -67,16 +67,16 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ConstructorCopy() { - Assert.Throws(() => ((ExifProfile)null).DeepClone()); + Assert.Throws(() => ((ExifProfile)null).Clone()); ExifProfile profile = GetExifProfile(); - ExifProfile clone = profile.DeepClone(); + ExifProfile clone = profile.Clone(); TestProfile(clone); profile.SetValue(ExifTag.ColorSpace, (ushort)2); - clone = profile.DeepClone(); + clone = profile.Clone(); TestProfile(clone); } From 061436f7656828f4f07586b87e118479b6b3f836 Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Thu, 20 Sep 2018 11:08:49 -0700 Subject: [PATCH 071/185] Fix issue on mono <= 5.14 when reading multiple png data chunks. Fixes #598 --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 139 +++++++++++------- .../Formats/Png/Zlib/ZlibInflateStream.cs | 16 +- 2 files changed, 98 insertions(+), 57 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 9281927012..76162eacbb 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -187,6 +187,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private bool hasTrans; + /// + /// The next chunk of data to return + /// + private PngChunk? nextChunk; + /// /// Initializes a new instance of the class. /// @@ -223,67 +228,66 @@ namespace SixLabors.ImageSharp.Formats.Png Image image = null; try { - using (var deframeStream = new ZlibInflateStream(this.currentStream)) + while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) { - while (!this.isEndChunkReached && this.TryReadChunk(out PngChunk chunk)) + try { - try + switch (chunk.Type) { - switch (chunk.Type) - { - case PngChunkType.Header: - this.ReadHeaderChunk(pngMetaData, chunk.Data.Array); - this.ValidateHeader(); - break; - case PngChunkType.Physical: - this.ReadPhysicalChunk(metaData, chunk.Data.GetSpan()); - break; - case PngChunkType.Gamma: - this.ReadGammaChunk(pngMetaData, chunk.Data.GetSpan()); - break; - case PngChunkType.Data: - if (image is null) - { - this.InitializeImage(metaData, out image); - } - - deframeStream.AllocateNewBytes(chunk.Length); + case PngChunkType.Header: + this.ReadHeaderChunk(pngMetaData, chunk.Data.Array); + this.ValidateHeader(); + break; + case PngChunkType.Physical: + this.ReadPhysicalChunk(metaData, chunk.Data.GetSpan()); + break; + case PngChunkType.Gamma: + this.ReadGammaChunk(pngMetaData, chunk.Data.GetSpan()); + break; + case PngChunkType.Data: + if (image is null) + { + this.InitializeImage(metaData, out image); + } + + using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk)) + { + deframeStream.AllocateNewBytes(chunk.Length); this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); - this.currentStream.Read(this.crcBuffer, 0, 4); - break; - case PngChunkType.Palette: - byte[] pal = new byte[chunk.Length]; - Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); - this.palette = pal; - break; - case PngChunkType.PaletteAlpha: - byte[] alpha = new byte[chunk.Length]; - Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); - this.paletteAlpha = alpha; - this.AssignTransparentMarkers(alpha); - break; - case PngChunkType.Text: - this.ReadTextChunk(metaData, chunk.Data.Array, chunk.Length); - break; - case PngChunkType.Exif: - if (!this.ignoreMetadata) - { - byte[] exifData = new byte[chunk.Length]; - Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length); - metaData.ExifProfile = new ExifProfile(exifData); - } - - break; - case PngChunkType.End: - this.isEndChunkReached = true; - break; - } - } - finally - { - chunk.Data?.Dispose(); // Data is rented in ReadChunkData() + } + break; + case PngChunkType.Palette: + byte[] pal = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, pal, 0, chunk.Length); + this.palette = pal; + break; + case PngChunkType.PaletteAlpha: + byte[] alpha = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, alpha, 0, chunk.Length); + this.paletteAlpha = alpha; + this.AssignTransparentMarkers(alpha); + break; + case PngChunkType.Text: + this.ReadTextChunk(metaData, chunk.Data.Array, chunk.Length); + break; + case PngChunkType.Exif: + if (!this.ignoreMetadata) + { + byte[] exifData = new byte[chunk.Length]; + Buffer.BlockCopy(chunk.Data.Array, 0, exifData, 0, chunk.Length); + metaData.ExifProfile = new ExifProfile(exifData); + } + + break; + case PngChunkType.End: + this.isEndChunkReached = true; + break; } } + finally + { + chunk.Data?.Dispose(); // Data is rented in ReadChunkData() + } } if (image is null) @@ -1366,6 +1370,25 @@ namespace SixLabors.ImageSharp.Formats.Png metadata.Properties.Add(new ImageProperty(name, value)); } + /// + /// Reads the next data chunk. + /// + /// Count of bytes in the next data chunk, or 0 if there are no more data chunks left. + private int ReadNextDataChunk() + { + this.currentStream.Read(this.crcBuffer, 0, 4); + + this.TryReadChunk(out PngChunk chunk); + + if (chunk.Type == PngChunkType.Data) + { + return chunk.Length; + } + + this.nextChunk = chunk; + return 0; + } + /// /// Reads a chunk from the stream. /// @@ -1375,6 +1398,12 @@ namespace SixLabors.ImageSharp.Formats.Png /// private bool TryReadChunk(out PngChunk chunk) { + if (this.nextChunk != null) + { + chunk = this.nextChunk.Value; + return true; + } + int length = this.ReadChunkLength(); if (length == -1) diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs index 55432d60b1..c2f6d6d881 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs @@ -52,13 +52,20 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// private int currentDataRemaining; + /// + /// Delegate to get more data once we've exhausted the current data remaining + /// + private Func getData; + /// /// Initializes a new instance of the class. /// /// The inner raw stream - public ZlibInflateStream(Stream innerStream) + /// A delegate to get more data from the inner stream + public ZlibInflateStream(Stream innerStream, Func getData) { this.innerStream = innerStream; + this.getData = getData; } /// @@ -112,7 +119,12 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { if (this.currentDataRemaining == 0) { - return 0; + this.currentDataRemaining = this.getData(); + + if (this.currentDataRemaining == 0) + { + return 0; + } } int bytesToRead = Math.Min(count, this.currentDataRemaining); From 6e47624413df86782db4e034110506bb26e868cb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Sep 2018 21:07:31 +0100 Subject: [PATCH 072/185] Add Clone overloads for new configuration. --- src/ImageSharp/Configuration.cs | 2 +- src/ImageSharp/ImageFrame{TPixel}.cs | 50 +++++++---- src/ImageSharp/Image{TPixel}.cs | 88 ++++++++++--------- tests/ImageSharp.Tests/ConfigurationTests.cs | 2 +- .../Image/ImageTests.WrapMemory.cs | 2 +- tests/ImageSharp.Tests/Image/ImageTests.cs | 4 +- .../ImageProviders/TestImageProvider.cs | 2 +- 7 files changed, 86 insertions(+), 64 deletions(-) diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 1b009bfedd..354701747a 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp /// Creates a shallow copy of the /// /// A new configuration instance - public Configuration ShallowCopy() + public Configuration Clone() { return new Configuration { diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 132ab598e5..9ff6c6511c 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -95,6 +95,10 @@ namespace SixLabors.ImageSharp /// /// Initializes a new instance of the class wrapping an existing buffer. /// + /// The configuration providing initialization code which allows extending the library. + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The memory source. internal ImageFrame(Configuration configuration, int width, int height, MemorySource memorySource) : this(configuration, width, height, memorySource, new ImageFrameMetaData()) { @@ -103,12 +107,12 @@ namespace SixLabors.ImageSharp /// /// Initializes a new instance of the class wrapping an existing buffer. /// - internal ImageFrame( - Configuration configuration, - int width, - int height, - MemorySource memorySource, - ImageFrameMetaData metaData) + /// The configuration providing initialization code which allows extending the library. + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The memory source. + /// The meta data. + internal ImageFrame(Configuration configuration, int width, int height, MemorySource memorySource, ImageFrameMetaData metaData) { Guard.NotNull(configuration, nameof(configuration)); Guard.MustBeGreaterThan(width, 0, nameof(width)); @@ -247,25 +251,47 @@ namespace SixLabors.ImageSharp /// public override string ToString() => $"ImageFrame<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + /// + /// Clones the current instance. + /// + /// The + internal ImageFrame Clone() => this.Clone(this.configuration); + + /// + /// Clones the current instance. + /// + /// The configuration providing initialization code which allows extending the library. + /// The + internal ImageFrame Clone(Configuration configuration) => new ImageFrame(configuration, this); + /// /// Returns a copy of the image frame in the given pixel format. /// /// The pixel format. /// The internal ImageFrame CloneAs() + where TPixel2 : struct, IPixel => this.CloneAs(this.configuration); + + /// + /// Returns a copy of the image frame in the given pixel format. + /// + /// The pixel format. + /// The configuration providing initialization code which allows extending the library. + /// The + internal ImageFrame CloneAs(Configuration configuration) where TPixel2 : struct, IPixel { if (typeof(TPixel2) == typeof(TPixel)) { - return this.Clone() as ImageFrame; + return this.Clone(configuration) as ImageFrame; } - var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.Clone()); + var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.Clone()); ParallelFor.WithTemporaryBuffer( 0, this.Height, - this.configuration, + configuration, this.Width, (int y, IMemoryOwner tempRowBuffer) => { @@ -298,12 +324,6 @@ namespace SixLabors.ImageSharp }); } - /// - /// Clones the current instance. - /// - /// The - internal ImageFrame Clone() => new ImageFrame(this.configuration, this); - /// void IDisposable.Dispose() => this.Dispose(); } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 8bc5a40bdc..3ee369fdad 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -11,7 +11,6 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; namespace SixLabors.ImageSharp { @@ -23,15 +22,12 @@ namespace SixLabors.ImageSharp where TPixel : struct, IPixel { private readonly Configuration configuration; - private readonly ImageFrameCollection frames; /// /// Initializes a new instance of the class /// with the height and the width of the image. /// - /// - /// The configuration providing initialization code which allows extending the library. - /// + /// The configuration providing initialization code which allows extending the library. /// The width of the image in pixels. /// The height of the image in pixels. public Image(Configuration configuration, int width, int height) @@ -43,9 +39,7 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the class /// with the height and the width of the image. /// - /// - /// The configuration providing initialization code which allows extending the library. - /// + /// The configuration providing initialization code which allows extending the library. /// The width of the image in pixels. /// The height of the image in pixels. /// The color to initialize the pixels with. @@ -69,9 +63,7 @@ namespace SixLabors.ImageSharp /// Initializes a new instance of the class /// with the height and the width of the image. /// - /// - /// The configuration providing initialization code which allows extending the library. - /// + /// The configuration providing initialization code which allows extending the library. /// The width of the image in pixels. /// The height of the image in pixels. /// The images metadata. @@ -80,37 +72,41 @@ namespace SixLabors.ImageSharp this.configuration = configuration ?? Configuration.Default; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata ?? new ImageMetaData(); - this.frames = new ImageFrameCollection(this, width, height, default(TPixel)); + this.Frames = new ImageFrameCollection(this, width, height, default(TPixel)); } /// /// Initializes a new instance of the class /// wrapping an external /// + /// The configuration providing initialization code which allows extending the library. + /// The memory source. + /// The width of the image in pixels. + /// The height of the image in pixels. + /// The images metadata. internal Image(Configuration configuration, MemorySource memorySource, int width, int height, ImageMetaData metadata) { this.configuration = configuration; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata; - this.frames = new ImageFrameCollection(this, width, height, memorySource); + this.Frames = new ImageFrameCollection(this, width, height, memorySource); } /// /// Initializes a new instance of the class /// with the height and the width of the image. /// - /// - /// The configuration providing initialization code which allows extending the library. - /// + /// The configuration providing initialization code which allows extending the library. /// The width of the image in pixels. /// The height of the image in pixels. /// The color to initialize the pixels with. /// The images metadata. - internal Image(Configuration configuration, int width, int height, TPixel backgroundColor, ImageMetaData metadata) { + internal Image(Configuration configuration, int width, int height, TPixel backgroundColor, ImageMetaData metadata) + { this.configuration = configuration ?? Configuration.Default; this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata ?? new ImageMetaData(); - this.frames = new ImageFrameCollection(this, width, height, backgroundColor); + this.Frames = new ImageFrameCollection(this, width, height, backgroundColor); } /// @@ -126,7 +122,7 @@ namespace SixLabors.ImageSharp this.PixelType = new PixelTypeInfo(Unsafe.SizeOf() * 8); this.MetaData = metadata ?? new ImageMetaData(); - this.frames = new ImageFrameCollection(this, frames); + this.Frames = new ImageFrameCollection(this, frames); } /// @@ -138,10 +134,10 @@ namespace SixLabors.ImageSharp public PixelTypeInfo PixelType { get; } /// - public int Width => this.frames.RootFrame.Width; + public int Width => this.Frames.RootFrame.Width; /// - public int Height => this.frames.RootFrame.Height; + public int Height => this.Frames.RootFrame.Height; /// public ImageMetaData MetaData { get; } @@ -149,12 +145,12 @@ namespace SixLabors.ImageSharp /// /// Gets the frames. /// - public ImageFrameCollection Frames => this.frames; + public ImageFrameCollection Frames { get; } /// /// Gets the root frame. /// - private IPixelSource PixelSource => this.frames?.RootFrame ?? throw new ObjectDisposedException(nameof(Image)); + private IPixelSource PixelSource => this.Frames?.RootFrame ?? throw new ObjectDisposedException(nameof(Image)); /// /// Gets or sets the pixel at the specified position. @@ -187,16 +183,17 @@ namespace SixLabors.ImageSharp /// Clones the current image /// /// Returns a new image with all the same metadata as the original. - public Image Clone() - { - IEnumerable> clonedFrames = this.frames.Select(x => x.Clone()); - return new Image(this.configuration, this.MetaData.Clone(), clonedFrames); - } + public Image Clone() => this.Clone(this.configuration); - /// - public override string ToString() + /// + /// Clones the current image with the given configueation. + /// + /// The configuration providing initialization code which allows extending the library. + /// Returns a new with all the same pixel data as the original. + public Image Clone(Configuration configuration) { - return $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + IEnumerable> clonedFrames = this.Frames.Select(x => x.Clone(configuration)); + return new Image(configuration, this.MetaData.Clone(), clonedFrames); } /// @@ -205,22 +202,27 @@ namespace SixLabors.ImageSharp /// The pixel format. /// The public Image CloneAs() - where TPixel2 : struct, IPixel - { - IEnumerable> clonedFrames = this.frames.Select(x => x.CloneAs()); - var target = new Image(this.configuration, this.MetaData.Clone(), clonedFrames); - - return target; - } + where TPixel2 : struct, IPixel => this.CloneAs(this.configuration); /// - /// Releases managed resources. + /// Returns a copy of the image in the given pixel format. /// - public void Dispose() + /// The pixel format. + /// The configuration providing initialization code which allows extending the library. + /// The + public Image CloneAs(Configuration configuration) + where TPixel2 : struct, IPixel { - this.frames.Dispose(); + IEnumerable> clonedFrames = this.Frames.Select(x => x.CloneAs(configuration)); + return new Image(configuration, this.MetaData.Clone(), clonedFrames); } + /// + public void Dispose() => this.Frames.Dispose(); + + /// + public override string ToString() => $"Image<{typeof(TPixel).Name}>: {this.Width}x{this.Height}"; + /// /// Switches the buffers used by the image and the pixelSource meaning that the Image will "own" the buffer from the pixelSource and the pixelSource will now own the Images buffer. /// @@ -229,9 +231,9 @@ namespace SixLabors.ImageSharp { Guard.NotNull(pixelSource, nameof(pixelSource)); - for (int i = 0; i < this.frames.Count; i++) + for (int i = 0; i < this.Frames.Count; i++) { - this.frames[i].SwapOrCopyPixelsBufferFrom(pixelSource.frames[i]); + this.Frames[i].SwapOrCopyPixelsBufferFrom(pixelSource.Frames[i]); } } } diff --git a/tests/ImageSharp.Tests/ConfigurationTests.cs b/tests/ImageSharp.Tests/ConfigurationTests.cs index 6a8479b2b2..963d674466 100644 --- a/tests/ImageSharp.Tests/ConfigurationTests.cs +++ b/tests/ImageSharp.Tests/ConfigurationTests.cs @@ -23,7 +23,7 @@ namespace SixLabors.ImageSharp.Tests { // the shallow copy of configuration should behave exactly like the default configuration, // so by using the copy, we test both the default and the copy. - this.DefaultConfiguration = Configuration.CreateDefaultInstance().ShallowCopy(); + this.DefaultConfiguration = Configuration.CreateDefaultInstance().Clone(); this.ConfigurationEmpty = new Configuration(); } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 69572425c9..16d999ad25 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void WrapMemory_CreatedImageIsCorrect() { - Configuration cfg = Configuration.Default.ShallowCopy(); + Configuration cfg = Configuration.Default.Clone(); var metaData = new ImageMetaData(); var array = new Rgba32[25]; diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index ed142ed974..f3c04d5e14 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Configuration_Width_Height() { - Configuration configuration = Configuration.Default.ShallowCopy(); + Configuration configuration = Configuration.Default.Clone(); using (var image = new Image(configuration, 11, 23)) { @@ -48,7 +48,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void Configuration_Width_Height_BackroundColor() { - Configuration configuration = Configuration.Default.ShallowCopy(); + Configuration configuration = Configuration.Default.Clone(); Rgba32 color = Rgba32.Aquamarine; using (var image = new Image(configuration, 11, 23, color)) diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs index ab0cc42f93..30ac0856c7 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests public virtual string SourceFileOrDescription => ""; - public Configuration Configuration { get; set; } = Configuration.Default.ShallowCopy(); + public Configuration Configuration { get; set; } = Configuration.Default.Clone(); /// /// Utility instance to provide informations about the test image & manage input/output From 4979e1971f5fa16fb440ee1bdee15a51d0287c56 Mon Sep 17 00:00:00 2001 From: Curtis Wensley Date: Thu, 20 Sep 2018 13:44:33 -0700 Subject: [PATCH 073/185] Fixes to make all unit tests pass - Also fix some formatting warnings --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 23 +++++++--- .../Formats/Png/Zlib/ZlibInflateStream.cs | 44 +++++++++++-------- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 76162eacbb..ef2f226556 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -252,9 +252,10 @@ namespace SixLabors.ImageSharp.Formats.Png using (var deframeStream = new ZlibInflateStream(this.currentStream, this.ReadNextDataChunk)) { - deframeStream.AllocateNewBytes(chunk.Length); + deframeStream.AllocateNewBytes(chunk.Length); this.ReadScanlines(deframeStream.CompressedStream, image.Frames.RootFrame); } + break; case PngChunkType.Palette: byte[] pal = new byte[chunk.Length]; @@ -1376,16 +1377,23 @@ namespace SixLabors.ImageSharp.Formats.Png /// Count of bytes in the next data chunk, or 0 if there are no more data chunks left. private int ReadNextDataChunk() { - this.currentStream.Read(this.crcBuffer, 0, 4); + if (this.nextChunk != null) + { + return 0; + } - this.TryReadChunk(out PngChunk chunk); + this.currentStream.Read(this.crcBuffer, 0, 4); - if (chunk.Type == PngChunkType.Data) + if (this.TryReadChunk(out PngChunk chunk)) { - return chunk.Length; + if (chunk.Type == PngChunkType.Data) + { + return chunk.Length; + } + + this.nextChunk = chunk; } - this.nextChunk = chunk; return 0; } @@ -1401,6 +1409,9 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.nextChunk != null) { chunk = this.nextChunk.Value; + + this.nextChunk = null; + return true; } diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs index c2f6d6d881..a92220a595 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs @@ -42,11 +42,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// private bool isDisposed; - /// - /// Whether the crc value has been read. - /// - private bool crcRead; - /// /// The current data remaining to be read /// @@ -119,17 +114,36 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { if (this.currentDataRemaining == 0) { - this.currentDataRemaining = this.getData(); + // last buffer was read in its entirety, let's make sure we don't actually have more + this.currentDataRemaining = this.getData(); - if (this.currentDataRemaining == 0) - { - return 0; - } + if (this.currentDataRemaining == 0) + { + return 0; + } } int bytesToRead = Math.Min(count, this.currentDataRemaining); this.currentDataRemaining -= bytesToRead; - return this.innerStream.Read(buffer, offset, bytesToRead); + int bytesRead = this.innerStream.Read(buffer, offset, bytesToRead); + + // keep reading data until we've reached the end of the stream or filled the buffer + while (this.currentDataRemaining == 0 && bytesRead < count) + { + this.currentDataRemaining = this.getData(); + + if (this.currentDataRemaining == 0) + { + return bytesRead; + } + + offset += bytesRead; + bytesToRead = Math.Min(count - bytesRead, this.currentDataRemaining); + this.currentDataRemaining -= bytesToRead; + bytesRead += this.innerStream.Read(buffer, offset, bytesToRead); + } + + return bytesRead; } /// @@ -165,14 +179,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib { this.compressedStream.Dispose(); this.compressedStream = null; - - if (!this.crcRead) - { - // Consume the trailing 4 bytes - this.innerStream.Read(ChecksumBuffer, 0, 4); - this.currentDataRemaining -= 4; - this.crcRead = true; - } } } From b36a58bcded1e7c4199e2fe3359dafa61dba88f0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 20 Sep 2018 23:09:28 +0100 Subject: [PATCH 074/185] Clone => DeepClone --- src/ImageSharp/Formats/Bmp/BmpMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifFrameMetaData.cs | 2 +- src/ImageSharp/Formats/Gif/GifMetaData.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegMetaData.cs | 2 +- src/ImageSharp/Formats/Png/PngMetaData.cs | 2 +- src/ImageSharp/IDeepCloneable.cs | 4 ++-- src/ImageSharp/ImageFrameCollection.cs | 18 ++++++------------ src/ImageSharp/ImageFrame{TPixel}.cs | 4 ++-- src/ImageSharp/Image{TPixel}.cs | 4 ++-- src/ImageSharp/MetaData/ImageFrameMetaData.cs | 4 ++-- src/ImageSharp/MetaData/ImageMetaData.cs | 8 ++++---- .../MetaData/Profiles/Exif/ExifProfile.cs | 4 ++-- .../MetaData/Profiles/Exif/ExifValue.cs | 2 +- .../MetaData/Profiles/ICC/IccProfile.cs | 2 +- .../Transforms/AffineTransformProcessor.cs | 4 ++-- .../Processors/Transforms/CropProcessor.cs | 4 ++-- .../Transforms/ProjectiveTransformProcessor.cs | 4 ++-- .../Processors/Transforms/ResizeProcessor.cs | 4 ++-- .../Formats/Bmp/BmpMetaDataTests.cs | 2 +- .../Formats/Gif/GifFrameMetaDataTests.cs | 2 +- .../Formats/Gif/GifMetaDataTests.cs | 2 +- .../Formats/Jpg/JpegMetaDataTests.cs | 2 +- .../Formats/Png/PngMetaDataTests.cs | 2 +- .../MetaData/ImageFrameMetaDataTests.cs | 2 +- .../MetaData/ImageMetaDataTests.cs | 4 ++-- .../MetaData/Profiles/Exif/ExifProfileTests.cs | 6 +++--- 26 files changed, 46 insertions(+), 52 deletions(-) diff --git a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs index 134c8904b8..8b33e30fa6 100644 --- a/src/ImageSharp/Formats/Bmp/BmpMetaData.cs +++ b/src/ImageSharp/Formats/Bmp/BmpMetaData.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Bmp public BmpBitsPerPixel BitsPerPixel { get; set; } = BmpBitsPerPixel.Pixel24; /// - public IDeepCloneable Clone() => new BmpMetaData(this); + public IDeepCloneable DeepClone() => new BmpMetaData(this); // TODO: Colors used once we support encoding palette bmps. } diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs index 47af2bbdc0..0042c6a108 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetaData.cs @@ -49,6 +49,6 @@ namespace SixLabors.ImageSharp.Formats.Gif public GifDisposalMethod DisposalMethod { get; set; } /// - public IDeepCloneable Clone() => new GifFrameMetaData(this); + public IDeepCloneable DeepClone() => new GifFrameMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Gif/GifMetaData.cs b/src/ImageSharp/Formats/Gif/GifMetaData.cs index 7a91a3a75e..bb7fb50518 100644 --- a/src/ImageSharp/Formats/Gif/GifMetaData.cs +++ b/src/ImageSharp/Formats/Gif/GifMetaData.cs @@ -45,6 +45,6 @@ namespace SixLabors.ImageSharp.Formats.Gif public int GlobalColorTableLength { get; set; } /// - public IDeepCloneable Clone() => new GifMetaData(this); + public IDeepCloneable DeepClone() => new GifMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs index 5cef3355a0..fcad29e5d0 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetaData.cs @@ -27,6 +27,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg public int Quality { get; set; } = 75; /// - public IDeepCloneable Clone() => new JpegMetaData(this); + public IDeepCloneable DeepClone() => new JpegMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngMetaData.cs b/src/ImageSharp/Formats/Png/PngMetaData.cs index e9f0dc6c42..9c76765146 100644 --- a/src/ImageSharp/Formats/Png/PngMetaData.cs +++ b/src/ImageSharp/Formats/Png/PngMetaData.cs @@ -43,6 +43,6 @@ namespace SixLabors.ImageSharp.Formats.Png public float Gamma { get; set; } /// - public IDeepCloneable Clone() => new PngMetaData(this); + public IDeepCloneable DeepClone() => new PngMetaData(this); } } \ No newline at end of file diff --git a/src/ImageSharp/IDeepCloneable.cs b/src/ImageSharp/IDeepCloneable.cs index 04c60a6252..a792fc044d 100644 --- a/src/ImageSharp/IDeepCloneable.cs +++ b/src/ImageSharp/IDeepCloneable.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp /// Creates a new that is a deep copy of the current instance. /// /// The . - T Clone(); + T DeepClone(); } /// @@ -26,6 +26,6 @@ namespace SixLabors.ImageSharp /// Creates a new object that is a deep copy of the current instance. /// /// The . - IDeepCloneable Clone(); + IDeepCloneable DeepClone(); } } \ No newline at end of file diff --git a/src/ImageSharp/ImageFrameCollection.cs b/src/ImageSharp/ImageFrameCollection.cs index 59571ce92e..bbe05ce435 100644 --- a/src/ImageSharp/ImageFrameCollection.cs +++ b/src/ImageSharp/ImageFrameCollection.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp public ImageFrame InsertFrame(int index, ImageFrame source) { this.ValidateFrame(source); - ImageFrame clonedFrame = source.Clone(); + ImageFrame clonedFrame = source.Clone(this.parent.GetConfiguration()); this.frames.Insert(index, clonedFrame); return clonedFrame; } @@ -107,7 +107,7 @@ namespace SixLabors.ImageSharp public ImageFrame AddFrame(ImageFrame source) { this.ValidateFrame(source); - ImageFrame clonedFrame = source.Clone(); + ImageFrame clonedFrame = source.Clone(this.parent.GetConfiguration()); this.frames.Add(clonedFrame); return clonedFrame; } @@ -155,10 +155,7 @@ namespace SixLabors.ImageSharp /// /// true if the contains the specified frame; otherwise, false. /// - public bool Contains(ImageFrame frame) - { - return this.frames.Contains(frame); - } + public bool Contains(ImageFrame frame) => this.frames.Contains(frame); /// /// Moves an from to . @@ -195,7 +192,7 @@ namespace SixLabors.ImageSharp this.frames.Remove(frame); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { frame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { frame }); } /// @@ -208,7 +205,7 @@ namespace SixLabors.ImageSharp { ImageFrame frame = this[index]; ImageFrame clonedFrame = frame.Clone(); - return new Image(this.parent.GetConfiguration(), this.parent.MetaData.Clone(), new[] { clonedFrame }); + return new Image(this.parent.GetConfiguration(), this.parent.MetaData.DeepClone(), new[] { clonedFrame }); } /// @@ -217,10 +214,7 @@ namespace SixLabors.ImageSharp /// /// The new . /// - public ImageFrame CreateFrame() - { - return this.CreateFrame(default); - } + public ImageFrame CreateFrame() => this.CreateFrame(default); /// /// Creates a new and appends it to the end of the collection. diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 9ff6c6511c..5f1aa5a38e 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -139,7 +139,7 @@ namespace SixLabors.ImageSharp this.MemoryAllocator = configuration.MemoryAllocator; this.PixelBuffer = this.MemoryAllocator.Allocate2D(source.PixelBuffer.Width, source.PixelBuffer.Height); source.PixelBuffer.GetSpan().CopyTo(this.PixelBuffer.GetSpan()); - this.MetaData = source.MetaData.Clone(); + this.MetaData = source.MetaData.DeepClone(); } /// @@ -286,7 +286,7 @@ namespace SixLabors.ImageSharp return this.Clone(configuration) as ImageFrame; } - var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.Clone()); + var target = new ImageFrame(configuration, this.Width, this.Height, this.MetaData.DeepClone()); ParallelFor.WithTemporaryBuffer( 0, diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 3ee369fdad..9d4c1ef0b3 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp public Image Clone(Configuration configuration) { IEnumerable> clonedFrames = this.Frames.Select(x => x.Clone(configuration)); - return new Image(configuration, this.MetaData.Clone(), clonedFrames); + return new Image(configuration, this.MetaData.DeepClone(), clonedFrames); } /// @@ -214,7 +214,7 @@ namespace SixLabors.ImageSharp where TPixel2 : struct, IPixel { IEnumerable> clonedFrames = this.Frames.Select(x => x.CloneAs(configuration)); - return new Image(configuration, this.MetaData.Clone(), clonedFrames); + return new Image(configuration, this.MetaData.DeepClone(), clonedFrames); } /// diff --git a/src/ImageSharp/MetaData/ImageFrameMetaData.cs b/src/ImageSharp/MetaData/ImageFrameMetaData.cs index 26c717f2a4..f1f884be68 100644 --- a/src/ImageSharp/MetaData/ImageFrameMetaData.cs +++ b/src/ImageSharp/MetaData/ImageFrameMetaData.cs @@ -33,12 +33,12 @@ namespace SixLabors.ImageSharp.MetaData foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value.Clone()); + this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); } } /// - public ImageFrameMetaData Clone() => new ImageFrameMetaData(this); + public ImageFrameMetaData DeepClone() => new ImageFrameMetaData(this); /// /// Gets the metadata value associated with the specified key. diff --git a/src/ImageSharp/MetaData/ImageMetaData.cs b/src/ImageSharp/MetaData/ImageMetaData.cs index 44c1738cf0..73549d98aa 100644 --- a/src/ImageSharp/MetaData/ImageMetaData.cs +++ b/src/ImageSharp/MetaData/ImageMetaData.cs @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.MetaData foreach (KeyValuePair meta in other.formatMetaData) { - this.formatMetaData.Add(meta.Key, meta.Value.Clone()); + this.formatMetaData.Add(meta.Key, meta.Value.DeepClone()); } foreach (ImageProperty property in other.Properties) @@ -68,8 +68,8 @@ namespace SixLabors.ImageSharp.MetaData this.Properties.Add(property); } - this.ExifProfile = other.ExifProfile?.Clone(); - this.IccProfile = other.IccProfile?.Clone(); + this.ExifProfile = other.ExifProfile?.DeepClone(); + this.IccProfile = other.IccProfile?.DeepClone(); } /// @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.MetaData } /// - public ImageMetaData Clone() => new ImageMetaData(this); + public ImageMetaData DeepClone() => new ImageMetaData(this); /// /// Looks up a property with the provided name. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs index 7b71a78eb9..b48b146f11 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifProfile.cs @@ -70,7 +70,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif foreach (ExifValue value in other.Values) { - this.values.Add(value.Clone()); + this.values.Add(value.DeepClone()); } } @@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public ExifProfile Clone() => new ExifProfile(this); + public ExifProfile DeepClone() => new ExifProfile(this); /// /// Synchronizes the profiles with the specified meta data. diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs index 88827820c3..ccacfd0bf9 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifValue.cs @@ -229,7 +229,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif } /// - public ExifValue Clone() => new ExifValue(this); + public ExifValue DeepClone() => new ExifValue(this); /// /// Creates a new diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 3885303d45..44990b7ecc 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } /// - public IccProfile Clone() => new IccProfile(this); + public IccProfile DeepClone() => new IccProfile(this); #if !NETSTANDARD1_1 diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 3993ab1a8d..a7e1589259 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -51,10 +51,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.Clone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 0c52123755..df1ac32746 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -36,10 +36,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.Clone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.CropRectangle.Width, this.CropRectangle.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 042ce2ff6d..15816cb4dd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -51,10 +51,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // We will always be creating the clone even for mutate because we may need to resize the canvas IEnumerable> frames = - source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.Clone())); + source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.TargetDimensions.Width, this.TargetDimensions.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index fd3c34d6c1..b1c0632c66 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -215,10 +215,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { // We will always be creating the clone even for mutate because we may need to resize the canvas - IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.Clone())); + IEnumerable> frames = source.Frames.Select(x => new ImageFrame(source.GetConfiguration(), this.Width, this.Height, x.MetaData.DeepClone())); // Use the overload to prevent an extra frame being added - return new Image(source.GetConfiguration(), source.MetaData.Clone(), frames); + return new Image(source.GetConfiguration(), source.MetaData.DeepClone(), frames); } /// diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs index ca36a1eb5f..991768a11a 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpMetaDataTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Bmp public void CloneIsDeep() { var meta = new BmpMetaData() { BitsPerPixel = BmpBitsPerPixel.Pixel24 }; - var clone = (BmpMetaData)meta.Clone(); + var clone = (BmpMetaData)meta.DeepClone(); clone.BitsPerPixel = BmpBitsPerPixel.Pixel32; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs index 4879a56739..a39fc47b40 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifFrameMetaDataTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif ColorTableLength = 2 }; - var clone = (GifFrameMetaData)meta.Clone(); + var clone = (GifFrameMetaData)meta.DeepClone(); clone.FrameDelay = 2; clone.DisposalMethod = GifDisposalMethod.RestoreToPrevious; diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs index 4f42753164..29db32b4ab 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifMetaDataTests.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Gif GlobalColorTableLength = 2 }; - var clone = (GifMetaData)meta.Clone(); + var clone = (GifMetaData)meta.DeepClone(); clone.RepeatCount = 2; clone.ColorTableMode = GifColorTableMode.Local; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs index 054e79f514..431de4be31 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetaDataTests.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg public void CloneIsDeep() { var meta = new JpegMetaData() { Quality = 50 }; - var clone = (JpegMetaData)meta.Clone(); + var clone = (JpegMetaData)meta.DeepClone(); clone.Quality = 99; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs index 4b209613ae..a21bb9acbe 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetaDataTests.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png ColorType = PngColorType.GrayscaleWithAlpha, Gamma = 2 }; - var clone = (PngMetaData)meta.Clone(); + var clone = (PngMetaData)meta.DeepClone(); clone.BitDepth = PngBitDepth.Bit2; clone.ColorType = PngColorType.Palette; diff --git a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs index 428b7c431a..8c49039603 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageFrameMetaDataTests.cs @@ -37,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests public void CloneIsDeep() { var metaData = new ImageFrameMetaData(); - ImageFrameMetaData clone = metaData.Clone(); + ImageFrameMetaData clone = metaData.DeepClone(); Assert.False(metaData.GetFormatMetaData(GifFormat.Instance).Equals(clone.GetFormatMetaData(GifFormat.Instance))); } } diff --git a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs index 79fd7b7d2b..b9619cb3f8 100644 --- a/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs +++ b/tests/ImageSharp.Tests/MetaData/ImageMetaDataTests.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.Clone(); + ImageMetaData clone = metaData.DeepClone(); Assert.Equal(exifProfile.ToByteArray(), clone.ExifProfile.ToByteArray()); Assert.Equal(4, clone.HorizontalResolution); @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Tests metaData.VerticalResolution = 2; metaData.Properties.Add(imageProperty); - ImageMetaData clone = metaData.Clone(); + ImageMetaData clone = metaData.DeepClone(); clone.HorizontalResolution = 2; clone.VerticalResolution = 4; diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs index ee41c1759f..c10ffb6c8e 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/Exif/ExifProfileTests.cs @@ -67,16 +67,16 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void ConstructorCopy() { - Assert.Throws(() => ((ExifProfile)null).Clone()); + Assert.Throws(() => ((ExifProfile)null).DeepClone()); ExifProfile profile = GetExifProfile(); - ExifProfile clone = profile.Clone(); + ExifProfile clone = profile.DeepClone(); TestProfile(clone); profile.SetValue(ExifTag.ColorSpace, (ushort)2); - clone = profile.Clone(); + clone = profile.DeepClone(); TestProfile(clone); } From d3290243d8640f5455126b7aff4b0c342c6e5e71 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Fri, 21 Sep 2018 23:40:25 +0200 Subject: [PATCH 075/185] covariant interface: IDeepCloneable --- src/ImageSharp/IDeepCloneable.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/IDeepCloneable.cs b/src/ImageSharp/IDeepCloneable.cs index a792fc044d..f80247a5d0 100644 --- a/src/ImageSharp/IDeepCloneable.cs +++ b/src/ImageSharp/IDeepCloneable.cs @@ -7,8 +7,8 @@ namespace SixLabors.ImageSharp /// A generic interface for a deeply cloneable type. /// /// The type of object to clone. - public interface IDeepCloneable - where T : class, IDeepCloneable + public interface IDeepCloneable + where T : class { /// /// Creates a new that is a deep copy of the current instance. From f8c08beaf03d102c2c2bb082985140efcc009abb Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 00:07:25 +0200 Subject: [PATCH 076/185] skip tests in ReferenceDecoderBenchmarks --- .../TestUtilities/Tests/ReferenceDecoderBenchmarks.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs index 724c2e4144..033f0866a3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/ReferenceDecoderBenchmarks.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests private ITestOutputHelper Output { get; } public const string SkipBenchmarks = -#if false +#if true "Benchmark, enable manually!"; #else null; From 141073fd34cb4e14a39be9d226c4fb7389e60148 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 00:28:44 +0200 Subject: [PATCH 077/185] use ParallelHelper in BinaryThresholdProcessor and OilPaintingProcessor --- .../Binarization/BinaryThresholdProcessor.cs | 43 ++++--- .../Effects/OilPaintingProcessor.cs | 110 ++++++++++-------- 2 files changed, 84 insertions(+), 69 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs index c4f4266d98..60754b3bf2 100644 --- a/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Binarization/BinaryThresholdProcessor.cs @@ -2,10 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Threading.Tasks; + using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Binarization @@ -56,7 +56,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization public TPixel LowerColor { get; set; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply( + ImageFrame source, + Rectangle sourceRectangle, + Configuration configuration) { float threshold = this.Threshold * 255F; TPixel upper = this.UpperColor; @@ -70,25 +73,29 @@ namespace SixLabors.ImageSharp.Processing.Processors.Binarization bool isAlphaOnly = typeof(TPixel) == typeof(Alpha8); - ParallelFor.WithConfiguration( - startY, - endY, + var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); + + ParallelHelper.IterateRows( + workingRect, configuration, - y => + rows => { - Span row = source.GetPixelRowSpan(y); - Rgba32 rgba = default; - - for (int x = startX; x < endX; x++) + for (int y = rows.Min; y < rows.Max; y++) { - ref TPixel color = ref row[x]; - color.ToRgba32(ref rgba); + Span row = source.GetPixelRowSpan(y); + Rgba32 rgba = default; + + for (int x = startX; x < endX; x++) + { + ref TPixel color = ref row[x]; + color.ToRgba32(ref rgba); - // Convert to grayscale using ITU-R Recommendation BT.709 if required - float luminance = isAlphaOnly - ? rgba.A - : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); - color = luminance >= threshold ? upper : lower; + // Convert to grayscale using ITU-R Recommendation BT.709 if required + float luminance = isAlphaOnly + ? rgba.A + : (.2126F * rgba.R) + (.7152F * rgba.G) + (.0722F * rgba.B); + color = luminance >= threshold ? upper : lower; + } } }); } diff --git a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs index 59898e9fc1..6ad4dcba97 100644 --- a/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Effects/OilPaintingProcessor.cs @@ -3,11 +3,11 @@ using System; using System.Numerics; -using System.Threading.Tasks; + using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Effects @@ -49,7 +49,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects public int BrushSize { get; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply( + ImageFrame source, + Rectangle sourceRectangle, + Configuration configuration) { if (this.BrushSize <= 0 || this.BrushSize > source.Height || this.BrushSize > source.Width) { @@ -70,69 +73,74 @@ namespace SixLabors.ImageSharp.Processing.Processors.Effects { source.CopyTo(targetPixels); - ParallelFor.WithConfiguration( - startY, - maxY, + var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); + ParallelHelper.IterateRows( + workingRect, configuration, - y => - { - Span sourceRow = source.GetPixelRowSpan(y); - Span targetRow = targetPixels.GetRowSpan(y); - - for (int x = startX; x < endX; x++) + rows => { - int maxIntensity = 0; - int maxIndex = 0; + for (int y = rows.Min; y < rows.Max; y++) + { + Span sourceRow = source.GetPixelRowSpan(y); + Span targetRow = targetPixels.GetRowSpan(y); - int[] intensityBin = new int[levels]; - float[] redBin = new float[levels]; - float[] blueBin = new float[levels]; - float[] greenBin = new float[levels]; + for (int x = startX; x < endX; x++) + { + int maxIntensity = 0; + int maxIndex = 0; - for (int fy = 0; fy <= radius; fy++) - { - int fyr = fy - radius; - int offsetY = y + fyr; + int[] intensityBin = new int[levels]; + float[] redBin = new float[levels]; + float[] blueBin = new float[levels]; + float[] greenBin = new float[levels]; - offsetY = offsetY.Clamp(0, maxY); + for (int fy = 0; fy <= radius; fy++) + { + int fyr = fy - radius; + int offsetY = y + fyr; - Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); + offsetY = offsetY.Clamp(0, maxY); - for (int fx = 0; fx <= radius; fx++) - { - int fxr = fx - radius; - int offsetX = x + fxr; - offsetX = offsetX.Clamp(0, maxX); + Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); - var vector = sourceOffsetRow[offsetX].ToVector4(); + for (int fx = 0; fx <= radius; fx++) + { + int fxr = fx - radius; + int offsetX = x + fxr; + offsetX = offsetX.Clamp(0, maxX); - float sourceRed = vector.X; - float sourceBlue = vector.Z; - float sourceGreen = vector.Y; + var vector = sourceOffsetRow[offsetX].ToVector4(); - int currentIntensity = (int)MathF.Round((sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); + float sourceRed = vector.X; + float sourceBlue = vector.Z; + float sourceGreen = vector.Y; - intensityBin[currentIntensity]++; - blueBin[currentIntensity] += sourceBlue; - greenBin[currentIntensity] += sourceGreen; - redBin[currentIntensity] += sourceRed; + int currentIntensity = (int)MathF.Round( + (sourceBlue + sourceGreen + sourceRed) / 3F * (levels - 1)); - if (intensityBin[currentIntensity] > maxIntensity) - { - maxIntensity = intensityBin[currentIntensity]; - maxIndex = currentIntensity; - } - } + intensityBin[currentIntensity]++; + blueBin[currentIntensity] += sourceBlue; + greenBin[currentIntensity] += sourceGreen; + redBin[currentIntensity] += sourceRed; - float red = MathF.Abs(redBin[maxIndex] / maxIntensity); - float green = MathF.Abs(greenBin[maxIndex] / maxIntensity); - float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); + if (intensityBin[currentIntensity] > maxIntensity) + { + maxIntensity = intensityBin[currentIntensity]; + maxIndex = currentIntensity; + } + } - ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); + float red = MathF.Abs(redBin[maxIndex] / maxIntensity); + float green = MathF.Abs(greenBin[maxIndex] / maxIntensity); + float blue = MathF.Abs(blueBin[maxIndex] / maxIntensity); + + ref TPixel pixel = ref targetRow[x]; + pixel.PackFromVector4( + new Vector4(red, green, blue, sourceRow[x].ToVector4().W)); + } + } } - } - }); + }); Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); } From 63db6000744a4216d8fd73e31e55d7d25096b417 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 00:39:56 +0200 Subject: [PATCH 078/185] use ParallelHelper in BackgroundColorProcessor --- .../Overlays/BackgroundColorProcessor.cs | 38 +++++++++++-------- 1 file changed, 23 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs index ecbeebeb06..4adddd1536 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/BackgroundColorProcessor.cs @@ -6,6 +6,7 @@ using System.Buffers; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -67,6 +68,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays int width = maxX - minX; + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + using (IMemoryOwner colors = source.MemoryAllocator.Allocate(width)) using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) { @@ -74,25 +77,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays Span colorSpan = colors.GetSpan(); Span amountSpan = amount.GetSpan(); - // TODO: Use Span.Fill? - for (int i = 0; i < width; i++) - { - colorSpan[i] = this.Color; - amountSpan[i] = this.GraphicsOptions.BlendPercentage; - } + colorSpan.Fill(this.Color); + amountSpan.Fill(this.GraphicsOptions.BlendPercentage); PixelBlender blender = PixelOperations.Instance.GetPixelBlender(this.GraphicsOptions); - ParallelFor.WithConfiguration( - minY, - maxY, + + ParallelHelper.IterateRows( + workingRect, configuration, - y => - { - Span destination = source.GetPixelRowSpan(y - startY).Slice(minX - startX, width); + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span destination = + source.GetPixelRowSpan(y - startY).Slice(minX - startX, width); - // This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one - blender.Blend(source.MemoryAllocator, destination, colors.GetSpan(), destination, amount.GetSpan()); - }); + // This switched color & destination in the 2nd and 3rd places because we are applying the target color under the current one + blender.Blend( + source.MemoryAllocator, + destination, + colors.GetSpan(), + destination, + amount.GetSpan()); + } + }); } } } From 900c7d984dad9f78210c01f8422ad321a63076a8 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 00:55:42 +0200 Subject: [PATCH 079/185] WIP applying ParallelHelper to Convolution processors --- .../Convolution/Convolution2DProcessor.cs | 174 +++++++++++++----- .../Convolution/Convolution2PassProcessor.cs | 45 +++++ .../Convolution/ConvolutionProcessor.cs | 53 ++++++ .../EdgeDetectorCompassProcessor.cs | 37 ++++ .../Processors/Convolution/DetectEdgesTest.cs | 2 - 5 files changed, 259 insertions(+), 52 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index b5a2725437..24505eac05 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -3,12 +3,12 @@ using System; using System.Numerics; -using System.Threading.Tasks; + using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution @@ -42,7 +42,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution public DenseMatrix KernelY { get; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + protected override void OnFrameApply( + ImageFrame source, + Rectangle sourceRectangle, + Configuration configuration) { int kernelYHeight = this.KernelY.Rows; int kernelYWidth = this.KernelY.Columns; @@ -58,71 +61,142 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution int maxY = endY - 1; int maxX = endX - 1; - using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Width, source.Height)) + using (Buffer2D targetPixels = + configuration.MemoryAllocator.Allocate2D(source.Width, source.Height)) { source.CopyTo(targetPixels); + var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); + +#if true + ParallelHelper.IterateRows( + workingRectangle, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span sourceRow = source.GetPixelRowSpan(y); + Span targetRow = targetPixels.GetRowSpan(y); + + for (int x = startX; x < endX; x++) + { + float rX = 0; + float gX = 0; + float bX = 0; + float rY = 0; + float gY = 0; + float bY = 0; + + // Apply each matrix multiplier to the color components for each pixel. + for (int fy = 0; fy < kernelYHeight; fy++) + { + int fyr = fy - radiusY; + int offsetY = y + fyr; + + offsetY = offsetY.Clamp(0, maxY); + Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); + + for (int fx = 0; fx < kernelXWidth; fx++) + { + int fxr = fx - radiusX; + int offsetX = x + fxr; + + offsetX = offsetX.Clamp(0, maxX); + Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); + + if (fy < kernelXHeight) + { + Vector4 kx = this.KernelX[fy, fx] * currentColor; + rX += kx.X; + gX += kx.Y; + bX += kx.Z; + } + + if (fx < kernelYWidth) + { + Vector4 ky = this.KernelY[fy, fx] * currentColor; + rY += ky.X; + gY += ky.Y; + bY += ky.Z; + } + } + } + + float red = MathF.Sqrt((rX * rX) + (rY * rY)); + float green = MathF.Sqrt((gX * gX) + (gY * gY)); + float blue = MathF.Sqrt((bX * bX) + (bY * bY)); + + ref TPixel pixel = ref targetRow[x]; + pixel.PackFromVector4( + new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); + } + } + }); +#else ParallelFor.WithConfiguration( startY, endY, configuration, y => - { - Span sourceRow = source.GetPixelRowSpan(y); - Span targetRow = targetPixels.GetRowSpan(y); - - for (int x = startX; x < endX; x++) { - float rX = 0; - float gX = 0; - float bX = 0; - float rY = 0; - float gY = 0; - float bY = 0; - - // Apply each matrix multiplier to the color components for each pixel. - for (int fy = 0; fy < kernelYHeight; fy++) - { - int fyr = fy - radiusY; - int offsetY = y + fyr; - - offsetY = offsetY.Clamp(0, maxY); - Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); + Span sourceRow = source.GetPixelRowSpan(y); + Span targetRow = targetPixels.GetRowSpan(y); - for (int fx = 0; fx < kernelXWidth; fx++) + for (int x = startX; x < endX; x++) + { + float rX = 0; + float gX = 0; + float bX = 0; + float rY = 0; + float gY = 0; + float bY = 0; + + // Apply each matrix multiplier to the color components for each pixel. + for (int fy = 0; fy < kernelYHeight; fy++) { - int fxr = fx - radiusX; - int offsetX = x + fxr; + int fyr = fy - radiusY; + int offsetY = y + fyr; - offsetX = offsetX.Clamp(0, maxX); - Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); + offsetY = offsetY.Clamp(0, maxY); + Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); - if (fy < kernelXHeight) + for (int fx = 0; fx < kernelXWidth; fx++) { - Vector4 kx = this.KernelX[fy, fx] * currentColor; - rX += kx.X; - gX += kx.Y; - bX += kx.Z; - } - - if (fx < kernelYWidth) - { - Vector4 ky = this.KernelY[fy, fx] * currentColor; - rY += ky.X; - gY += ky.Y; - bY += ky.Z; + int fxr = fx - radiusX; + int offsetX = x + fxr; + + offsetX = offsetX.Clamp(0, maxX); + Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); + + if (fy < kernelXHeight) + { + Vector4 kx = this.KernelX[fy, fx] * currentColor; + rX += kx.X; + gX += kx.Y; + bX += kx.Z; + } + + if (fx < kernelYWidth) + { + Vector4 ky = this.KernelY[fy, fx] * currentColor; + rY += ky.X; + gY += ky.Y; + bY += ky.Z; + } } } - } - float red = MathF.Sqrt((rX * rX) + (rY * rY)); - float green = MathF.Sqrt((gX * gX) + (gY * gY)); - float blue = MathF.Sqrt((bX * bX) + (bY * bY)); + float red = MathF.Sqrt((rX * rX) + (rY * rY)); + float green = MathF.Sqrt((gX * gX) + (gY * gY)); + float blue = MathF.Sqrt((bX * bX) + (bY * bY)); - ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); - } - }); + ref TPixel pixel = ref targetRow[x]; + pixel.PackFromVector4( + new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); + } + }); +#endif Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 0808c07d03..9263c262d7 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -6,6 +6,7 @@ using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Processors; @@ -82,6 +83,49 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution int maxY = endY - 1; int maxX = endX - 1; + var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); + +#if true + ParallelHelper.IterateRows( + workingRectangle, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span targetRow = targetPixels.GetRowSpan(y); + + for (int x = startX; x < endX; x++) + { + Vector4 destination = default; + + // Apply each matrix multiplier to the color components for each pixel. + for (int fy = 0; fy < kernelHeight; fy++) + { + int fyr = fy - radiusY; + int offsetY = y + fyr; + + offsetY = offsetY.Clamp(0, maxY); + Span row = sourcePixels.GetRowSpan(offsetY); + + for (int fx = 0; fx < kernelWidth; fx++) + { + int fxr = fx - radiusX; + int offsetX = x + fxr; + + offsetX = offsetX.Clamp(0, maxX); + + Vector4 currentColor = row[offsetX].ToVector4().Premultiply(); + destination += kernel[fy, fx] * currentColor; + } + } + + ref TPixel pixel = ref targetRow[x]; + pixel.PackFromVector4(destination.UnPremultiply()); + } + } + }); +#else ParallelFor.WithConfiguration( startY, endY, @@ -119,6 +163,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution pixel.PackFromVector4(destination.UnPremultiply()); } }); +#endif } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index 31e638a0ad..64c9f4632b 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -6,6 +6,7 @@ using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Processors; @@ -52,6 +53,57 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { source.CopyTo(targetPixels); + var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); + +#if true + ParallelHelper.IterateRows( + workingRect, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span sourceRow = source.GetPixelRowSpan(y); + Span targetRow = targetPixels.GetRowSpan(y); + + for (int x = startX; x < endX; x++) + { + float red = 0; + float green = 0; + float blue = 0; + + // Apply each matrix multiplier to the color components for each pixel. + for (int fy = 0; fy < kernelLength; fy++) + { + int fyr = fy - radius; + int offsetY = y + fyr; + + offsetY = offsetY.Clamp(0, maxY); + Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); + + for (int fx = 0; fx < kernelLength; fx++) + { + int fxr = fx - radius; + int offsetX = x + fxr; + + offsetX = offsetX.Clamp(0, maxX); + + Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); + currentColor *= this.KernelXY[fy, fx]; + + red += currentColor.X; + green += currentColor.Y; + blue += currentColor.Z; + } + } + + ref TPixel pixel = ref targetRow[x]; + pixel.PackFromVector4( + new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); + } + } + }); +#else ParallelFor.WithConfiguration( startY, endY, @@ -96,6 +148,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); } }); +#endif Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs index 316de422f5..28a72922fa 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.ImageSharp.Processing.Processors.Filters; @@ -124,6 +125,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution shiftY = 0; } + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + // Additional runs. // ReSharper disable once ForCanBeConvertedToForeach for (int i = 1; i < kernels.Length; i++) @@ -135,6 +138,39 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Buffer2D passPixels = pass.PixelBuffer; Buffer2D targetPixels = source.PixelBuffer; +#if true + ParallelHelper.IterateRows( + workingRect, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + int offsetY = y - shiftY; + + ref TPixel passPixelsBase = + ref MemoryMarshal.GetReference(passPixels.GetRowSpan(offsetY)); + ref TPixel targetPixelsBase = + ref MemoryMarshal.GetReference(targetPixels.GetRowSpan(offsetY)); + + for (int x = minX; x < maxX; x++) + { + int offsetX = x - shiftX; + + // Grab the max components of the two pixels + ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX); + ref TPixel currentTargetPixel = + ref Unsafe.Add(ref targetPixelsBase, offsetX); + + var pixelValue = Vector4.Max( + currentPassPixel.ToVector4(), + currentTargetPixel.ToVector4()); + + currentTargetPixel.PackFromVector4(pixelValue); + } + } + }); +#else ParallelFor.WithConfiguration( minY, maxY, @@ -161,6 +197,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution currentTargetPixel.PackFromVector4(pixelValue); } }); +#endif } } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs index a32239d96f..de72f6d09e 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Convolution/DetectEdgesTest.cs @@ -10,8 +10,6 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Convolution { - using SixLabors.ImageSharp.Advanced; - public class DetectEdgesTest : FileTestBase { private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.0456F); From 9e51f4b00284d182d3106a30c2ff663b8bfa3053 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 15:07:01 +0200 Subject: [PATCH 080/185] DetectEdgesTest.DetectEdges_InBox issue isolated in a failing test for ParallelHelper.IterateRows() --- .../Helpers/ParallelHelperTests.cs | 52 +++++++++++++++++++ .../TestUtilities/TestImageExtensions.cs | 16 ++++-- 2 files changed, 63 insertions(+), 5 deletions(-) diff --git a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs index 35bf1489bb..c843543299 100644 --- a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs @@ -9,6 +9,7 @@ using System.Threading; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; +using SixLabors.Memory; using SixLabors.Primitives; using Xunit; @@ -195,5 +196,56 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(expectedNumberOfSteps, actualNumberOfSteps); } + + public static readonly TheoryData IterateRectangularBuffer_Data = + new TheoryData() + { + { 8, 582, 453, 10, 10, 291, 226 }, // bounds in DetectEdgesTest.DetectEdges_InBox + { 2, 582, 453, 10, 10, 291, 226 }, + }; + + [Theory] + [MemberData(nameof(IterateRectangularBuffer_Data))] + public void IterateRectangularBuffer( + int maxDegreeOfParallelism, + int bufferWidth, + int bufferHeight, + int rectX, + int rectY, + int rectWidth, + int rectHeight) + { + MemoryAllocator memoryAllocator = Configuration.Default.MemoryAllocator; + + using (Buffer2D expected = memoryAllocator.Allocate2D(bufferWidth, bufferHeight, AllocationOptions.Clean)) + using (Buffer2D actual = memoryAllocator.Allocate2D(bufferWidth, bufferHeight, AllocationOptions.Clean)) + { + var rect = new Rectangle(rectX, rectY, rectWidth, rectHeight); + + for (int y = rectY; y < rect.Bottom; y++) + { + for (int x = rect.Left; x < rect.Right; x++) + { + expected[x, y] = y * 10000 + x; + } + } + + var settings = new ParallelExecutionSettings(maxDegreeOfParallelism, memoryAllocator); + + ParallelHelper.IterateRows(rect, settings, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + for (int x = rect.Left; x < rect.Right; x++) + { + actual[x, y] = y * 10000 + x; + } + } + }); + + TestImageExtensions.CompareBuffers(expected.Span, actual.Span); + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index a935873670..8b4b933446 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -441,14 +441,20 @@ namespace SixLabors.ImageSharp.Tests { Span actualPixels = image.GetPixelSpan(); - Assert.True(expectedPixels.Length == actualPixels.Length, "Buffer sizes are not equal!"); + CompareBuffers(expectedPixels, actualPixels); - for (int i = 0; i < expectedPixels.Length; i++) + return image; + } + + public static void CompareBuffers(Span expected, Span actual) + where T : struct, IEquatable + { + Assert.True(expected.Length == actual.Length, "Buffer sizes are not equal!"); + + for (int i = 0; i < expected.Length; i++) { - Assert.True(expectedPixels[i].Equals(actualPixels[i]), $"Pixels are different on position {i}!"); + Assert.True(expected[i].Equals(actual[i]), $"Buffers differ at position {i}!"); } - - return image; } /// From 0def05086668dd4361a0ad326ac6c02c877bb792 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 17:25:47 +0200 Subject: [PATCH 081/185] fixed ParallelHelper + improved tests --- .../Common/ParallelUtils/ParallelHelper.cs | 6 +- src/ImageSharp/Memory/RowInterval.cs | 6 + .../Helpers/ParallelHelperTests.cs | 111 ++++++++++++++++-- .../TestUtilities/TestImageExtensions.cs | 5 +- 4 files changed, 113 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs index a757f50c87..fbbc579465 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs @@ -44,6 +44,8 @@ namespace SixLabors.ImageSharp.ParallelUtils in ParallelExecutionSettings parallelSettings, Action body) { + DebugGuard.MustBeGreaterThan(rectangle.Width, 0, nameof(rectangle)); + int maxSteps = DivideCeil(rectangle.Width * rectangle.Height, parallelSettings.MinimumPixelsProcessedPerTask); int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); @@ -56,7 +58,7 @@ namespace SixLabors.ImageSharp.ParallelUtils return; } - int verticalStep = DivideRound(rectangle.Height, numOfSteps); + int verticalStep = DivideCeil(rectangle.Height, numOfSteps); var parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = numOfSteps }; @@ -102,7 +104,7 @@ namespace SixLabors.ImageSharp.ParallelUtils return; } - int verticalStep = DivideRound(rectangle.Height, numOfSteps); + int verticalStep = DivideCeil(rectangle.Height, numOfSteps); var parallelOptions = new ParallelOptions() { MaxDegreeOfParallelism = numOfSteps }; diff --git a/src/ImageSharp/Memory/RowInterval.cs b/src/ImageSharp/Memory/RowInterval.cs index 87b08251b3..273a6aa346 100644 --- a/src/ImageSharp/Memory/RowInterval.cs +++ b/src/ImageSharp/Memory/RowInterval.cs @@ -32,5 +32,11 @@ namespace SixLabors.ImageSharp.Memory /// Gets the difference ( - ) /// public int Height => this.Max - this.Min; + + /// + public override string ToString() + { + return $"RowInterval [{this.Min}->{this.Max}["; + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs index c843543299..ef6b133f75 100644 --- a/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ParallelHelperTests.cs @@ -13,11 +13,19 @@ using SixLabors.Memory; using SixLabors.Primitives; using Xunit; +using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.Helpers { public class ParallelHelperTests { + private readonly ITestOutputHelper Output; + + public ParallelHelperTests(ITestOutputHelper output) + { + this.Output = output; + } + /// /// maxDegreeOfParallelism, minY, maxY, expectedStepLength, expectedLastStepLength /// @@ -30,12 +38,13 @@ namespace SixLabors.ImageSharp.Tests.Helpers { 2, 10, 19, 5, 4 }, { 4, 0, 200, 50, 50 }, { 4, 123, 323, 50, 50 }, - { 4, 0, 1201, 300, 301 }, + { 4, 0, 1201, 301, 298 }, + { 8, 10, 236, 29, 23 } }; [Theory] [MemberData(nameof(IterateRows_OverMinimumPixelsLimit_Data))] - public void IterateRows_OverMinimumPixelsLimit( + public void IterateRows_OverMinimumPixelsLimit_IntervalsAreCorrect( int maxDegreeOfParallelism, int minY, int maxY, @@ -50,6 +59,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers var rectangle = new Rectangle(0, minY, 10, maxY - minY); int actualNumberOfSteps = 0; + ParallelHelper.IterateRows( rectangle, parallelSettings, @@ -68,6 +78,40 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(maxDegreeOfParallelism, actualNumberOfSteps); } + [Theory] + [MemberData(nameof(IterateRows_OverMinimumPixelsLimit_Data))] + public void IterateRows_OverMinimumPixelsLimit_ShouldVisitAllRows( + int maxDegreeOfParallelism, + int minY, + int maxY, + int expectedStepLength, + int expectedLastStepLength) + { + var parallelSettings = new ParallelExecutionSettings( + maxDegreeOfParallelism, + 1, + Configuration.Default.MemoryAllocator); + + var rectangle = new Rectangle(0, minY, 10, maxY - minY); + + + int[] expectedData = Enumerable.Repeat(0, minY).Concat(Enumerable.Range(minY, maxY - minY)).ToArray(); + int[] actualData = new int[maxY]; + + ParallelHelper.IterateRows( + rectangle, + parallelSettings, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + actualData[y] = y; + } + }); + + Assert.Equal(expectedData, actualData); + } + [Theory] [MemberData(nameof(IterateRows_OverMinimumPixelsLimit_Data))] public void IterateRowsWithTempBuffer_OverMinimumPixelsLimit( @@ -110,6 +154,40 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(actualNumberOfSteps, numberOfDifferentBuffers); } + [Theory] + [MemberData(nameof(IterateRows_OverMinimumPixelsLimit_Data))] + public void IterateRowsWithTempBuffer_OverMinimumPixelsLimit_ShouldVisitAllRows( + int maxDegreeOfParallelism, + int minY, + int maxY, + int expectedStepLength, + int expectedLastStepLength) + { + var parallelSettings = new ParallelExecutionSettings( + maxDegreeOfParallelism, + 1, + Configuration.Default.MemoryAllocator); + + var rectangle = new Rectangle(0, minY, 10, maxY - minY); + + int[] expectedData = Enumerable.Repeat(0, minY).Concat(Enumerable.Range(minY, maxY - minY)).ToArray(); + int[] actualData = new int[maxY]; + + ParallelHelper.IterateRowsWithTempBuffer( + rectangle, + parallelSettings, + (RowInterval rows, Memory buffer) => + { + for (int y = rows.Min; y < rows.Max; y++) + { + actualData[y] = y; + } + }); + + Assert.Equal(expectedData, actualData); + + } + public static TheoryData IterateRows_WithEffectiveMinimumPixelsLimit_Data = new TheoryData() { @@ -200,8 +278,11 @@ namespace SixLabors.ImageSharp.Tests.Helpers public static readonly TheoryData IterateRectangularBuffer_Data = new TheoryData() { - { 8, 582, 453, 10, 10, 291, 226 }, // bounds in DetectEdgesTest.DetectEdges_InBox + { 8, 582, 453, 10, 10, 291, 226 }, // boundary data from DetectEdgesTest.DetectEdges_InBox { 2, 582, 453, 10, 10, 291, 226 }, + { 16, 582, 453, 10, 10, 291, 226 }, + { 16, 582, 453, 10, 10, 1, 226 }, + { 16, 1, 453, 0, 10, 1, 226 }, }; [Theory] @@ -217,33 +298,39 @@ namespace SixLabors.ImageSharp.Tests.Helpers { MemoryAllocator memoryAllocator = Configuration.Default.MemoryAllocator; - using (Buffer2D expected = memoryAllocator.Allocate2D(bufferWidth, bufferHeight, AllocationOptions.Clean)) - using (Buffer2D actual = memoryAllocator.Allocate2D(bufferWidth, bufferHeight, AllocationOptions.Clean)) + using (Buffer2D expected = memoryAllocator.Allocate2D(bufferWidth, bufferHeight, AllocationOptions.Clean)) + using (Buffer2D actual = memoryAllocator.Allocate2D(bufferWidth, bufferHeight, AllocationOptions.Clean)) { var rect = new Rectangle(rectX, rectY, rectWidth, rectHeight); - - for (int y = rectY; y < rect.Bottom; y++) + + void FillRow(int y, Buffer2D buffer) { for (int x = rect.Left; x < rect.Right; x++) { - expected[x, y] = y * 10000 + x; + buffer[x, y] = new Point(x, y); } } + // Fill Expected data: + for (int y = rectY; y < rect.Bottom; y++) + { + FillRow(y, expected); + } + + // Fill actual data using IterateRows: var settings = new ParallelExecutionSettings(maxDegreeOfParallelism, memoryAllocator); ParallelHelper.IterateRows(rect, settings, rows => { + this.Output.WriteLine(rows.ToString()); for (int y = rows.Min; y < rows.Max; y++) { - for (int x = rect.Left; x < rect.Right; x++) - { - actual[x, y] = y * 10000 + x; - } + FillRow(y, actual); } }); + // Assert: TestImageExtensions.CompareBuffers(expected.Span, actual.Span); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 8b4b933446..2384333bfb 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -453,7 +453,10 @@ namespace SixLabors.ImageSharp.Tests for (int i = 0; i < expected.Length; i++) { - Assert.True(expected[i].Equals(actual[i]), $"Buffers differ at position {i}!"); + T x = expected[i]; + T a = actual[i]; + + Assert.True(x.Equals(a), $"Buffers differ at position {i}! Expected: {x} | Actual: {a}"); } } From b7c3914dfa100c916e71ca72c8d159b8c868648f Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 19:14:52 +0200 Subject: [PATCH 082/185] remove old implementations --- .../Common/ParallelUtils/ParallelHelper.cs | 3 +- .../Convolution/Convolution2DProcessor.cs | 65 ------------------- .../Convolution/Convolution2PassProcessor.cs | 40 ------------ .../Convolution/ConvolutionProcessor.cs | 47 -------------- .../EdgeDetectorCompassProcessor.cs | 29 --------- 5 files changed, 2 insertions(+), 182 deletions(-) diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs index fbbc579465..8512db5cc4 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs @@ -13,7 +13,8 @@ using SixLabors.Primitives; namespace SixLabors.ImageSharp.ParallelUtils { /// - /// Utility methods wrapping Parallel.For() execution optimized for image processing. + /// Utility methods for batched processing of pixel row intervals. + /// Parallel execution is optimized for image processing. /// Use this instead of direct calls! /// internal static class ParallelHelper diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 24505eac05..d2282ec0e1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -68,7 +68,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); -#if true ParallelHelper.IterateRows( workingRectangle, configuration, @@ -133,70 +132,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } } }); -#else - ParallelFor.WithConfiguration( - startY, - endY, - configuration, - y => - { - Span sourceRow = source.GetPixelRowSpan(y); - Span targetRow = targetPixels.GetRowSpan(y); - - for (int x = startX; x < endX; x++) - { - float rX = 0; - float gX = 0; - float bX = 0; - float rY = 0; - float gY = 0; - float bY = 0; - - // Apply each matrix multiplier to the color components for each pixel. - for (int fy = 0; fy < kernelYHeight; fy++) - { - int fyr = fy - radiusY; - int offsetY = y + fyr; - - offsetY = offsetY.Clamp(0, maxY); - Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); - - for (int fx = 0; fx < kernelXWidth; fx++) - { - int fxr = fx - radiusX; - int offsetX = x + fxr; - - offsetX = offsetX.Clamp(0, maxX); - Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); - - if (fy < kernelXHeight) - { - Vector4 kx = this.KernelX[fy, fx] * currentColor; - rX += kx.X; - gX += kx.Y; - bX += kx.Z; - } - - if (fx < kernelYWidth) - { - Vector4 ky = this.KernelY[fy, fx] * currentColor; - rY += ky.X; - gY += ky.Y; - bY += ky.Z; - } - } - } - - float red = MathF.Sqrt((rX * rX) + (rY * rY)); - float green = MathF.Sqrt((gX * gX) + (gY * gY)); - float blue = MathF.Sqrt((bX * bX) + (bY * bY)); - - ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4( - new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); - } - }); -#endif Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 9263c262d7..e45bb3ab2e 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -85,7 +85,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); -#if true ParallelHelper.IterateRows( workingRectangle, configuration, @@ -125,45 +124,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } } }); -#else - ParallelFor.WithConfiguration( - startY, - endY, - configuration, - y => - { - Span targetRow = targetPixels.GetRowSpan(y); - - for (int x = startX; x < endX; x++) - { - Vector4 destination = default; - - // Apply each matrix multiplier to the color components for each pixel. - for (int fy = 0; fy < kernelHeight; fy++) - { - int fyr = fy - radiusY; - int offsetY = y + fyr; - - offsetY = offsetY.Clamp(0, maxY); - Span row = sourcePixels.GetRowSpan(offsetY); - - for (int fx = 0; fx < kernelWidth; fx++) - { - int fxr = fx - radiusX; - int offsetX = x + fxr; - - offsetX = offsetX.Clamp(0, maxX); - - Vector4 currentColor = row[offsetX].ToVector4().Premultiply(); - destination += kernel[fy, fx] * currentColor; - } - } - - ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4(destination.UnPremultiply()); - } - }); -#endif } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index 64c9f4632b..bac9a86cfe 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -55,7 +55,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); -#if true ParallelHelper.IterateRows( workingRect, configuration, @@ -103,52 +102,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } } }); -#else - ParallelFor.WithConfiguration( - startY, - endY, - configuration, - y => - { - Span sourceRow = source.GetPixelRowSpan(y); - Span targetRow = targetPixels.GetRowSpan(y); - - for (int x = startX; x < endX; x++) - { - float red = 0; - float green = 0; - float blue = 0; - - // Apply each matrix multiplier to the color components for each pixel. - for (int fy = 0; fy < kernelLength; fy++) - { - int fyr = fy - radius; - int offsetY = y + fyr; - - offsetY = offsetY.Clamp(0, maxY); - Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); - - for (int fx = 0; fx < kernelLength; fx++) - { - int fxr = fx - radius; - int offsetX = x + fxr; - - offsetX = offsetX.Clamp(0, maxX); - - Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); - currentColor *= this.KernelXY[fy, fx]; - - red += currentColor.X; - green += currentColor.Y; - blue += currentColor.Z; - } - } - - ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4(new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); - } - }); -#endif Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs index 28a72922fa..ebf9c8dec2 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor.cs @@ -138,7 +138,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Buffer2D passPixels = pass.PixelBuffer; Buffer2D targetPixels = source.PixelBuffer; -#if true ParallelHelper.IterateRows( workingRect, configuration, @@ -170,34 +169,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution } } }); -#else - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - int offsetY = y - shiftY; - - ref TPixel passPixelsBase = ref MemoryMarshal.GetReference(passPixels.GetRowSpan(offsetY)); - ref TPixel targetPixelsBase = ref MemoryMarshal.GetReference(targetPixels.GetRowSpan(offsetY)); - - for (int x = minX; x < maxX; x++) - { - int offsetX = x - shiftX; - - // Grab the max components of the two pixels - ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, offsetX); - ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, offsetX); - - var pixelValue = Vector4.Max( - currentPassPixel.ToVector4(), - currentTargetPixel.ToVector4()); - - currentTargetPixel.PackFromVector4(pixelValue); - } - }); -#endif } } } From 45554f2eaa0a78b26db434fb7133d7d29c03481b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 19:42:45 +0200 Subject: [PATCH 083/185] adapt ParallelHelper in: FliterProcessor, GlowProcessor, VignetteProcessor --- .../Common/ParallelUtils/ParallelHelper.cs | 9 +++ .../Processors/Filters/FilterProcessor.cs | 28 ++++----- .../Processors/Overlays/GlowProcessor.cs | 60 ++++++++++-------- .../Processors/Overlays/VignetteProcessor.cs | 61 ++++++++++--------- 4 files changed, 89 insertions(+), 69 deletions(-) diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs index 8512db5cc4..3009e99fc4 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs @@ -127,6 +127,15 @@ namespace SixLabors.ImageSharp.ParallelUtils }); } + public static void IterateRowsWithTempBuffer( + Rectangle rectangle, + Configuration configuration, + Action> body) + where T : struct + { + IterateRowsWithTempBuffer(rectangle, configuration.GetParallelSettings(), body); + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int DivideCeil(int dividend, int divisor) { diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs index 6244d8bf76..e20b42eb7c 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor.cs @@ -5,6 +5,7 @@ using System; using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -35,25 +36,24 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); - int startY = interest.Y; - int endY = interest.Bottom; - int startX = interest.X; - int endX = interest.Right; + Matrix4x4 matrix = this.Matrix; - ParallelFor.WithConfiguration( - startY, - endY, + ParallelHelper.IterateRows( + interest, configuration, - y => + rows => { - Span row = source.GetPixelRowSpan(y); - - for (int x = startX; x < endX; x++) + for (int y = rows.Min; y < rows.Max; y++) { - ref TPixel pixel = ref row[x]; - var vector = Vector4.Transform(pixel.ToVector4(), matrix); - pixel.PackFromVector4(vector); + Span row = source.GetPixelRowSpan(y); + + for (int x = interest.X; x < interest.Right; x++) + { + ref TPixel pixel = ref row[x]; + var vector = Vector4.Transform(pixel.ToVector4(), matrix); + pixel.PackFromVector4(vector); + } } }); } diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index eb91fec043..d774a10ab8 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -7,6 +7,7 @@ using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.Memory; @@ -84,6 +85,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { + // TODO: can we simplify the rectangle calculation? + int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; @@ -113,36 +116,43 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } int width = maxX - minX; + int offsetX = minX - startX; + + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + using (IMemoryOwner rowColors = source.MemoryAllocator.Allocate(width)) { - // Be careful! Do not capture rowColorsSpan in the lambda below! - Span rowColorsSpan = rowColors.GetSpan(); + rowColors.GetSpan().Fill(glowColor); - for (int i = 0; i < width; i++) - { - rowColorsSpan[i] = glowColor; - } - - ParallelFor.WithTemporaryBuffer( - minY, - maxY, + ParallelHelper.IterateRowsWithTempBuffer( + workingRect, configuration, - width, - (y, amounts) => - { - Span amountsSpan = amounts.GetSpan(); - int offsetY = y - startY; - int offsetX = minX - startX; - for (int i = 0; i < width; i++) + (rows, amounts) => { - float distance = Vector2.Distance(center, new Vector2(i + offsetX, offsetY)); - amountsSpan[i] = (this.GraphicsOptions.BlendPercentage * (1 - (.95F * (distance / maxDistance)))).Clamp(0, 1); - } - - Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); - - this.blender.Blend(source.MemoryAllocator, destination, destination, rowColors.GetSpan(), amountsSpan); - }); + Span amountsSpan = amounts.Span; + + for (int y = rows.Min; y < rows.Max; y++) + { + int offsetY = y - startY; + + for (int i = 0; i < width; i++) + { + float distance = Vector2.Distance(center, new Vector2(i + offsetX, offsetY)); + amountsSpan[i] = + (this.GraphicsOptions.BlendPercentage * (1 - (.95F * (distance / maxDistance)))) + .Clamp(0, 1); + } + + Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); + + this.blender.Blend( + source.MemoryAllocator, + destination, + destination, + rowColors.GetSpan(), + amountsSpan); + } + }); } } } diff --git a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs index 63780df476..52dade4eff 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/VignetteProcessor.cs @@ -7,6 +7,7 @@ using System.Numerics; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; using SixLabors.Memory; @@ -115,43 +116,43 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays } int width = maxX - minX; + int offsetX = minX - startX; + + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + using (IMemoryOwner rowColors = source.MemoryAllocator.Allocate(width)) { - // Be careful! Do not capture rowColorsSpan in the lambda below! - Span rowColorsSpan = rowColors.GetSpan(); - - for (int i = 0; i < width; i++) - { - rowColorsSpan[i] = vignetteColor; - } + rowColors.GetSpan().Fill(vignetteColor); - ParallelFor.WithTemporaryBuffer( - minY, - maxY, + ParallelHelper.IterateRowsWithTempBuffer( + workingRect, configuration, - width, - (y, amounts) => + (rows, amounts) => { - Span amountsSpan = amounts.GetSpan(); - int offsetY = y - startY; - int offsetX = minX - startX; - for (int i = 0; i < width; i++) + Span amountsSpan = amounts.Span; + + for (int y = rows.Min; y < rows.Max; y++) { - float distance = Vector2.Distance(centre, new Vector2(i + offsetX, offsetY)); - amountsSpan[i] = - (this.GraphicsOptions.BlendPercentage * (.9F * (distance / maxDistance))).Clamp( - 0, - 1); + int offsetY = y - startY; + + for (int i = 0; i < width; i++) + { + float distance = Vector2.Distance(centre, new Vector2(i + offsetX, offsetY)); + amountsSpan[i] = + (this.GraphicsOptions.BlendPercentage * (.9F * (distance / maxDistance))).Clamp( + 0, + 1); + } + + Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); + + this.blender.Blend( + source.MemoryAllocator, + destination, + destination, + rowColors.GetSpan(), + amountsSpan); } - - Span destination = source.GetPixelRowSpan(offsetY).Slice(offsetX, width); - - this.blender.Blend( - source.MemoryAllocator, - destination, - destination, - rowColors.GetSpan(), - amountsSpan); }); } } From 61529a35dc6a85c86568f9e116c0fd1cb194879c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 22:14:41 +0200 Subject: [PATCH 084/185] validating tests for CropProcessor --- src/ImageSharp/Common/Helpers/ParallelFor.cs | 1 - .../Processors/Transforms/CropTest.cs | 24 +++++++++++++------ tests/Images/External | 2 +- 3 files changed, 18 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ParallelFor.cs b/src/ImageSharp/Common/Helpers/ParallelFor.cs index 579ae1257e..191875a950 100644 --- a/src/ImageSharp/Common/Helpers/ParallelFor.cs +++ b/src/ImageSharp/Common/Helpers/ParallelFor.cs @@ -2,7 +2,6 @@ using System.Buffers; using System.Threading.Tasks; -using SixLabors.ImageSharp.Memory; using SixLabors.Memory; namespace SixLabors.ImageSharp diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs index c154c8ff3c..2f78915120 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs @@ -1,24 +1,34 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using SixLabors.Primitives; + using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { + [GroupOutput("Transforms")] public class CropTest : FileTestBase { [Theory] - [WithFileCollection(nameof(DefaultFiles), DefaultPixelType)] - public void ImageShouldCrop(TestImageProvider provider) + [WithTestPatternImages(70, 30, PixelTypes.Rgba32, 0, 0, 70, 30)] + [WithTestPatternImages(50, 50, PixelTypes.Rgba32, -1, -1, 100, 200)] + [WithTestPatternImages(30, 70, PixelTypes.Rgba32, 7, 13, 20, 50)] + public void Crop(TestImageProvider provider, int x, int y, int w, int h) where TPixel : struct, IPixel { - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Crop(image.Width / 2, image.Height / 2)); - image.DebugSave(provider); - } + var rect = new Rectangle(x, y, w, h); + FormattableString info = $"X{x}Y{y}.W{w}H{h}"; + provider.RunValidatingProcessorTest( + ctx => ctx.Crop(rect), + info, + appendPixelTypeToFileName: false, + comparer: ImageComparer.Exact); } } } \ No newline at end of file diff --git a/tests/Images/External b/tests/Images/External index 6abc3bc0ac..2841a79efd 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 6abc3bc0ac253a24c9e88e68d7b7d853350a85da +Subproject commit 2841a79efd68d47c6552ce857869eb0d80f8de75 From 4c5f32441ab3230c1ec4fd7c92173470ae2052c4 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 22:52:30 +0200 Subject: [PATCH 085/185] ParallelHelper -> CropProcessor, additional FlipProcessor test --- .../ParallelExecutionSettings.cs | 20 ++++++++++-- .../Processors/Transforms/CropProcessor.cs | 32 ++++++++++--------- .../Processors/Transforms/FlipProcessor.cs | 3 ++ .../Processors/Transforms/FlipTests.cs | 19 +++++------ tests/Images/External | 2 +- 5 files changed, 49 insertions(+), 27 deletions(-) diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs index 89d5fc18d8..516c1446d2 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs @@ -12,7 +12,15 @@ namespace SixLabors.ImageSharp.ParallelUtils /// internal struct ParallelExecutionSettings { - public ParallelExecutionSettings(int maxDegreeOfParallelism, int minimumPixelsProcessedPerTask, MemoryAllocator memoryAllocator) + /// + /// Default value for . + /// + public const int DefaultMinimumPixelsProcessedPerTask = 2048; + + public ParallelExecutionSettings( + int maxDegreeOfParallelism, + int minimumPixelsProcessedPerTask, + MemoryAllocator memoryAllocator) { this.MaxDegreeOfParallelism = maxDegreeOfParallelism; this.MinimumPixelsProcessedPerTask = minimumPixelsProcessedPerTask; @@ -20,7 +28,7 @@ namespace SixLabors.ImageSharp.ParallelUtils } public ParallelExecutionSettings(int maxDegreeOfParallelism, MemoryAllocator memoryAllocator) - : this(maxDegreeOfParallelism, 2048, memoryAllocator) + : this(maxDegreeOfParallelism, DefaultMinimumPixelsProcessedPerTask, memoryAllocator) { } @@ -37,5 +45,13 @@ namespace SixLabors.ImageSharp.ParallelUtils /// Initialized with 2048 by default, the optimum value is operation specific. /// public int MinimumPixelsProcessedPerTask { get; } + + public ParallelExecutionSettings MultiplyMinimumPixelsPerTask(int multiplier) + { + return new ParallelExecutionSettings( + this.MaxDegreeOfParallelism, + this.MinimumPixelsProcessedPerTask * multiplier, + this.MemoryAllocator); + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 0c52123755..bb26216ece 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -4,8 +4,8 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -53,21 +53,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - int minY = Math.Max(this.CropRectangle.Y, sourceRectangle.Y); - int maxY = Math.Min(this.CropRectangle.Bottom, sourceRectangle.Bottom); - int minX = Math.Max(this.CropRectangle.X, sourceRectangle.X); - int maxX = Math.Min(this.CropRectangle.Right, sourceRectangle.Right); + var rect = Rectangle.Intersect(this.CropRectangle, sourceRectangle); - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - Span sourceRow = source.GetPixelRowSpan(y).Slice(minX); - Span targetRow = destination.GetPixelRowSpan(y - minY); - sourceRow.Slice(0, maxX - minX).CopyTo(targetRow); - }); + // Copying is cheap, we should process more pixels per task: + ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings().MultiplyMinimumPixelsPerTask(4); + + ParallelHelper.IterateRows( + rect, + parallelSettings, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span sourceRow = source.GetPixelRowSpan(y).Slice(rect.Left); + Span targetRow = destination.GetPixelRowSpan(y - rect.Top); + sourceRow.Slice(0, rect.Width).CopyTo(targetRow); + } + }); } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs index cea6df391f..442873676f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs @@ -57,8 +57,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int height = source.Height; int halfHeight = (int)Math.Ceiling(source.Height * .5F); + using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) { + + ParallelFor.WithConfiguration( 0, halfHeight, diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs index d7e7a724c4..3c932bfaa6 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/FlipTests.cs @@ -5,23 +5,24 @@ using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using Xunit; + // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { - using SixLabors.ImageSharp.Processing; - + [GroupOutput("Transforms")] public class FlipTests { - public static readonly TheoryData FlipValues - = new TheoryData - { - { FlipMode.None }, - { FlipMode.Vertical }, - { FlipMode.Horizontal }, - }; + public static readonly TheoryData FlipValues = + new TheoryData + { + FlipMode.None, + FlipMode.Vertical, + FlipMode.Horizontal, + }; [Theory] + [WithTestPatternImages(nameof(FlipValues), 20, 37, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(FlipValues), 53, 37, PixelTypes.Rgba32)] [WithTestPatternImages(nameof(FlipValues), 17, 32, PixelTypes.Rgba32)] public void Flip(TestImageProvider provider, FlipMode flipMode) diff --git a/tests/Images/External b/tests/Images/External index 2841a79efd..c1e14c0e43 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 2841a79efd68d47c6552ce857869eb0d80f8de75 +Subproject commit c1e14c0e431066c57585f255d3feb8d3a1860d50 From c267876a0edb2aa2c25e73ec93e3bfce199cbf85 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 23:07:24 +0200 Subject: [PATCH 086/185] better FlipProcessor implementation --- .../ParallelExecutionSettings.cs | 2 +- .../Processors/Transforms/FlipProcessor.cs | 67 ++++++------------- 2 files changed, 23 insertions(+), 46 deletions(-) diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs index 516c1446d2..9b2ae89d0a 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.ParallelUtils /// /// Default value for . /// - public const int DefaultMinimumPixelsProcessedPerTask = 2048; + public const int DefaultMinimumPixelsProcessedPerTask = 4096; public ParallelExecutionSettings( int maxDegreeOfParallelism, diff --git a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs index 442873676f..c6f5e9d7b8 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/FlipProcessor.cs @@ -2,9 +2,11 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Buffers; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -55,30 +57,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private void FlipX(ImageFrame source, Configuration configuration) { int height = source.Height; - int halfHeight = (int)Math.Ceiling(source.Height * .5F); - - using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) + using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(source.Width)) { + Span temp = tempBuffer.Memory.Span; - - ParallelFor.WithConfiguration( - 0, - halfHeight, - configuration, - y => - { - int newY = height - y - 1; - Span sourceRow = source.GetPixelRowSpan(y); - Span altSourceRow = source.GetPixelRowSpan(newY); - Span targetRow = targetPixels.GetRowSpan(y); - Span altTargetRow = targetPixels.GetRowSpan(newY); - - sourceRow.CopyTo(altTargetRow); - altSourceRow.CopyTo(targetRow); - }); - - Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); + for (int yTop = 0; yTop < height / 2; yTop++) + { + int yBottom = height - yTop - 1; + Span topRow = source.GetPixelRowSpan(yBottom); + Span bottomRow = source.GetPixelRowSpan(yTop); + topRow.CopyTo(temp); + bottomRow.CopyTo(topRow); + temp.CopyTo(bottomRow); + } } } @@ -89,31 +81,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The configuration. private void FlipY(ImageFrame source, Configuration configuration) { - int width = source.Width; - int height = source.Height; - int halfWidth = (int)Math.Ceiling(width * .5F); - - using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) - { - ParallelFor.WithConfiguration( - 0, - height, - configuration, - y => + ParallelHelper.IterateRows( + source.Bounds(), + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) { - Span sourceRow = source.GetPixelRowSpan(y); - Span targetRow = targetPixels.GetRowSpan(y); - - for (int x = 0; x < halfWidth; x++) - { - int newX = width - x - 1; - targetRow[x] = sourceRow[newX]; - targetRow[newX] = sourceRow[x]; - } - }); - - Buffer2D.SwapOrCopyContent(source.PixelBuffer, targetPixels); - } + source.GetPixelRowSpan(y).Reverse(); + } + }); } } } \ No newline at end of file From 7d415fbc27ca9815ffd6d819ed02f994bd2aba57 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 22 Sep 2018 23:45:46 +0200 Subject: [PATCH 087/185] ParallelHelper -> ProjectiveTransformProcessor, better RotateTests --- .../ProjectiveTransformProcessor.cs | 216 ++++++++++-------- .../Processors/Transforms/RotateTests.cs | 23 +- .../Transforms/ProjectiveTransformTests.cs | 2 +- tests/Images/External | 2 +- 4 files changed, 130 insertions(+), 113 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index 042ce2ff6d..4c789ef026 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -10,6 +10,7 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -75,28 +76,30 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (this.Sampler is NearestNeighborResampler) { - ParallelFor.WithConfiguration( - 0, - height, + ParallelHelper.IterateRows( + targetBounds, configuration, - y => - { - Span destRow = destination.GetPixelRowSpan(y); - - for (int x = 0; x < width; x++) + rows => { - var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix); + for (int y = rows.Min; y < rows.Max; y++) + { + Span destRow = destination.GetPixelRowSpan(y); - float z = MathF.Max(v3.Z, Epsilon); - int px = (int)MathF.Round(v3.X / z); - int py = (int)MathF.Round(v3.Y / z); + for (int x = 0; x < width; x++) + { + var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix); - if (sourceBounds.Contains(px, py)) - { - destRow[x] = source[px, py]; + float z = MathF.Max(v3.Z, Epsilon); + int px = (int)MathF.Round(v3.X / z); + int py = (int)MathF.Round(v3.Y / z); + + if (sourceBounds.Contains(px, py)) + { + destRow[x] = source[px, py]; + } + } } - } - }); + }); return; } @@ -121,92 +124,113 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) { - ParallelFor.WithConfiguration( - 0, - height, + ParallelHelper.IterateRows( + targetBounds, configuration, - y => - { - ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); - ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); - - for (int x = 0; x < width; x++) + rows => { - // Use the single precision position to calculate correct bounding pixels - // otherwise we get rogue pixels outside of the bounds. - var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix); - float z = MathF.Max(v3.Z, Epsilon); - - // Using Vector4 with dummy 0-s, because Vector2 SIMD implementation is not reliable: - Vector4 point = new Vector4(v3.X, v3.Y, 0, 0) / z; - - // Clamp sampling pixel radial extents to the source image edges - Vector4 maxXY = point + radius; - Vector4 minXY = point - radius; - - // max, maxY, minX, minY - var extents = new Vector4( - MathF.Floor(maxXY.X + .5F), - MathF.Floor(maxXY.Y + .5F), - MathF.Ceiling(minXY.X - .5F), - MathF.Ceiling(minXY.Y - .5F)); - - int right = (int)extents.X; - int bottom = (int)extents.Y; - int left = (int)extents.Z; - int top = (int)extents.W; - - extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); - - int maxX = (int)extents.X; - int maxY = (int)extents.Y; - int minX = (int)extents.Z; - int minY = (int)extents.W; - - if (minX == maxX || minY == maxY) - { - continue; - } - - // It appears these have to be calculated on-the-fly. - // Precalulating transformed weights would require prior knowledge of every transformed pixel location - // since they can be at sub-pixel positions on both axis. - // I've optimized where I can but am always open to suggestions. - if (yScale > 1 && xScale > 1) - { - CalculateWeightsDown(top, bottom, minY, maxY, point.Y, sampler, yScale, ref ySpanRef, yLength); - CalculateWeightsDown(left, right, minX, maxX, point.X, sampler, xScale, ref xSpanRef, xLength); - } - else + for (int y = rows.Min; y < rows.Max; y++) { - CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); - CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); - } + ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); + ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); + ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); - // Now multiply the results against the offsets - Vector4 sum = Vector4.Zero; - for (int yy = 0, j = minY; j <= maxY; j++, yy++) - { - float yWeight = Unsafe.Add(ref ySpanRef, yy); - - for (int xx = 0, i = minX; i <= maxX; i++, xx++) + for (int x = 0; x < width; x++) { - float xWeight = Unsafe.Add(ref xSpanRef, xx); - var vector = source[i, j].ToVector4(); - - // Values are first premultiplied to prevent darkening of edge pixels - Vector4 multiplied = vector.Premultiply(); - sum += multiplied * xWeight * yWeight; + // Use the single precision position to calculate correct bounding pixels + // otherwise we get rogue pixels outside of the bounds. + var v3 = Vector3.Transform(new Vector3(x, y, 1), matrix); + float z = MathF.Max(v3.Z, Epsilon); + + // Using Vector4 with dummy 0-s, because Vector2 SIMD implementation is not reliable: + Vector4 point = new Vector4(v3.X, v3.Y, 0, 0) / z; + + // Clamp sampling pixel radial extents to the source image edges + Vector4 maxXY = point + radius; + Vector4 minXY = point - radius; + + // max, maxY, minX, minY + var extents = new Vector4( + MathF.Floor(maxXY.X + .5F), + MathF.Floor(maxXY.Y + .5F), + MathF.Ceiling(minXY.X - .5F), + MathF.Ceiling(minXY.Y - .5F)); + + int right = (int)extents.X; + int bottom = (int)extents.Y; + int left = (int)extents.Z; + int top = (int)extents.W; + + extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); + + int maxX = (int)extents.X; + int maxY = (int)extents.Y; + int minX = (int)extents.Z; + int minY = (int)extents.W; + + if (minX == maxX || minY == maxY) + { + continue; + } + + // It appears these have to be calculated on-the-fly. + // Precalulating transformed weights would require prior knowledge of every transformed pixel location + // since they can be at sub-pixel positions on both axis. + // I've optimized where I can but am always open to suggestions. + if (yScale > 1 && xScale > 1) + { + CalculateWeightsDown( + top, + bottom, + minY, + maxY, + point.Y, + sampler, + yScale, + ref ySpanRef, + yLength); + + CalculateWeightsDown( + left, + right, + minX, + maxX, + point.X, + sampler, + xScale, + ref xSpanRef, + xLength); + } + else + { + CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); + CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); + } + + // Now multiply the results against the offsets + Vector4 sum = Vector4.Zero; + for (int yy = 0, j = minY; j <= maxY; j++, yy++) + { + float yWeight = Unsafe.Add(ref ySpanRef, yy); + + for (int xx = 0, i = minX; i <= maxX; i++, xx++) + { + float xWeight = Unsafe.Add(ref xSpanRef, xx); + var vector = source[i, j].ToVector4(); + + // Values are first premultiplied to prevent darkening of edge pixels + Vector4 multiplied = vector.Premultiply(); + sum += multiplied * xWeight * yWeight; + } + } + + ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); + + // Reverse the premultiplication + dest.PackFromVector4(sum.UnPremultiply()); } } - - ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); - - // Reverse the premultiplication - dest.PackFromVector4(sum.UnPremultiply()); - } - }); + }); } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateTests.cs index c0db205f9e..7801c71432 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/RotateTests.cs @@ -7,7 +7,8 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { - public class RotateTests : FileTestBase + [GroupOutput("Transforms")] + public class RotateTests { public static readonly TheoryData RotateAngles = new TheoryData @@ -25,29 +26,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms }; [Theory] - [WithTestPatternImages(nameof(RotateAngles), 100, 50, DefaultPixelType)] - [WithTestPatternImages(nameof(RotateAngles), 50, 100, DefaultPixelType)] + [WithTestPatternImages(nameof(RotateAngles), 100, 50, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(RotateAngles), 50, 100, PixelTypes.Rgba32)] public void Rotate_WithAngle(TestImageProvider provider, float value) where TPixel : struct, IPixel { - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Rotate(value)); - image.DebugSave(provider, value); - } + provider.RunValidatingProcessorTest(ctx => ctx.Rotate(value), value, appendPixelTypeToFileName: false); } [Theory] - [WithTestPatternImages(nameof(RotateEnumValues), 100, 50, DefaultPixelType)] - [WithTestPatternImages(nameof(RotateEnumValues), 50, 100, DefaultPixelType)] + [WithTestPatternImages(nameof(RotateEnumValues), 100, 50, PixelTypes.Rgba32)] + [WithTestPatternImages(nameof(RotateEnumValues), 50, 100, PixelTypes.Rgba32)] public void Rotate_WithRotateTypeEnum(TestImageProvider provider, RotateMode value) where TPixel : struct, IPixel { - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Rotate(value)); - image.DebugSave(provider, value); - } + provider.RunValidatingProcessorTest(ctx => ctx.Rotate(value), value, appendPixelTypeToFileName: false); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs index 8cf9dd62f5..5190a71e71 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/ProjectiveTransformTests.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms private static readonly ImageComparer TolerantComparer = ImageComparer.TolerantPercentage(0.5f, 3); private ITestOutputHelper Output { get; } - + public static readonly TheoryData ResamplerNames = new TheoryData { nameof(KnownResamplers.Bicubic), diff --git a/tests/Images/External b/tests/Images/External index c1e14c0e43..7f4d2d64c6 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit c1e14c0e431066c57585f255d3feb8d3a1860d50 +Subproject commit 7f4d2d64c6b820ca2b6827e6a8540a1013305ccf From 3e24c577f7f8492dfedc1bc68eb7f29eeab44851 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 00:45:01 +0200 Subject: [PATCH 088/185] ParallelHelper -> AffineTransformProcessor, RotateProcessor --- .../Transforms/AffineTransformProcessor.cs | 186 ++++++++++-------- .../Processors/Transforms/RotateProcessor.cs | 86 ++++---- 2 files changed, 152 insertions(+), 120 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 3993ab1a8d..b72b81a209 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -10,6 +10,7 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -78,23 +79,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (this.Sampler is NearestNeighborResampler) { - ParallelFor.WithConfiguration( - 0, - height, + ParallelHelper.IterateRows( + targetBounds, configuration, - y => - { - Span destRow = destination.GetPixelRowSpan(y); - - for (int x = 0; x < width; x++) + rows => { - var point = Point.Transform(new Point(x, y), matrix); - if (sourceBounds.Contains(point.X, point.Y)) + for (int y = rows.Min; y < rows.Max; y++) { - destRow[x] = source[point.X, point.Y]; + Span destRow = destination.GetPixelRowSpan(y); + + for (int x = 0; x < width; x++) + { + var point = Point.Transform(new Point(x, y), matrix); + if (sourceBounds.Contains(point.X, point.Y)) + { + destRow[x] = source[point.X, point.Y]; + } + } } - } - }); + }); return; } @@ -116,86 +119,107 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms using (Buffer2D yBuffer = memoryAllocator.Allocate2D(yLength, height)) using (Buffer2D xBuffer = memoryAllocator.Allocate2D(xLength, height)) { - ParallelFor.WithConfiguration( - 0, - height, + ParallelHelper.IterateRows( + targetBounds, configuration, - y => + rows => { - ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); - ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); - - for (int x = 0; x < width; x++) + for (int y = rows.Min; y < rows.Max; y++) { - // Use the single precision position to calculate correct bounding pixels - // otherwise we get rogue pixels outside of the bounds. - var point = Vector2.Transform(new Vector2(x, y), matrix); - - // Clamp sampling pixel radial extents to the source image edges - Vector2 maxXY = point + radius; - Vector2 minXY = point - radius; - - // max, maxY, minX, minY - var extents = new Vector4( - MathF.Floor(maxXY.X + .5F), - MathF.Floor(maxXY.Y + .5F), - MathF.Ceiling(minXY.X - .5F), - MathF.Ceiling(minXY.Y - .5F)); - - int right = (int)extents.X; - int bottom = (int)extents.Y; - int left = (int)extents.Z; - int top = (int)extents.W; - - extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); - - int maxX = (int)extents.X; - int maxY = (int)extents.Y; - int minX = (int)extents.Z; - int minY = (int)extents.W; - - if (minX == maxX || minY == maxY) - { - continue; - } + ref TPixel destRowRef = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); + ref float ySpanRef = ref MemoryMarshal.GetReference(yBuffer.GetRowSpan(y)); + ref float xSpanRef = ref MemoryMarshal.GetReference(xBuffer.GetRowSpan(y)); - // It appears these have to be calculated on-the-fly. - // Precalulating transformed weights would require prior knowledge of every transformed pixel location - // since they can be at sub-pixel positions on both axis. - // I've optimized where I can but am always open to suggestions. - if (yScale > 1 && xScale > 1) - { - CalculateWeightsDown(top, bottom, minY, maxY, point.Y, sampler, yScale, ref ySpanRef, yLength); - CalculateWeightsDown(left, right, minX, maxX, point.X, sampler, xScale, ref xSpanRef, xLength); - } - else + for (int x = 0; x < width; x++) { - CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); - CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); - } + // Use the single precision position to calculate correct bounding pixels + // otherwise we get rogue pixels outside of the bounds. + var point = Vector2.Transform(new Vector2(x, y), matrix); + + // Clamp sampling pixel radial extents to the source image edges + Vector2 maxXY = point + radius; + Vector2 minXY = point - radius; + + // max, maxY, minX, minY + var extents = new Vector4( + MathF.Floor(maxXY.X + .5F), + MathF.Floor(maxXY.Y + .5F), + MathF.Ceiling(minXY.X - .5F), + MathF.Ceiling(minXY.Y - .5F)); + + int right = (int)extents.X; + int bottom = (int)extents.Y; + int left = (int)extents.Z; + int top = (int)extents.W; + + extents = Vector4.Clamp(extents, Vector4.Zero, maxSource); + + int maxX = (int)extents.X; + int maxY = (int)extents.Y; + int minX = (int)extents.Z; + int minY = (int)extents.W; + + if (minX == maxX || minY == maxY) + { + continue; + } - // Now multiply the results against the offsets - Vector4 sum = Vector4.Zero; - for (int yy = 0, j = minY; j <= maxY; j++, yy++) - { - float yWeight = Unsafe.Add(ref ySpanRef, yy); + // It appears these have to be calculated on-the-fly. + // Precalculating transformed weights would require prior knowledge of every transformed pixel location + // since they can be at sub-pixel positions on both axis. + // I've optimized where I can but am always open to suggestions. + if (yScale > 1 && xScale > 1) + { + CalculateWeightsDown( + top, + bottom, + minY, + maxY, + point.Y, + sampler, + yScale, + ref ySpanRef, + yLength); + + CalculateWeightsDown( + left, + right, + minX, + maxX, + point.X, + sampler, + xScale, + ref xSpanRef, + xLength); + } + else + { + CalculateWeightsScaleUp(minY, maxY, point.Y, sampler, ref ySpanRef); + CalculateWeightsScaleUp(minX, maxX, point.X, sampler, ref xSpanRef); + } - for (int xx = 0, i = minX; i <= maxX; i++, xx++) + // Now multiply the results against the offsets + Vector4 sum = Vector4.Zero; + for (int yy = 0, j = minY; j <= maxY; j++, yy++) { - float xWeight = Unsafe.Add(ref xSpanRef, xx); - var vector = source[i, j].ToVector4(); + float yWeight = Unsafe.Add(ref ySpanRef, yy); + + for (int xx = 0, i = minX; i <= maxX; i++, xx++) + { + float xWeight = Unsafe.Add(ref xSpanRef, xx); + var vector = source[i, j].ToVector4(); - // Values are first premultiplied to prevent darkening of edge pixels - Vector4 multiplied = vector.Premultiply(); - sum += multiplied * xWeight * yWeight; + // Values are first premultiplied to prevent darkening of edge pixels + Vector4 multiplied = vector.Premultiply(); + sum += multiplied * xWeight * yWeight; + } } - } - ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); + ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); - // Reverse the premultiplication - dest.PackFromVector4(sum.UnPremultiply()); + // Reverse the premultiplication + dest.PackFromVector4(sum.UnPremultiply()); + } } }); } diff --git a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs index 93c847d598..2ad626755c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs @@ -5,6 +5,7 @@ using System; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.MetaData.Profiles.Exif; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; @@ -147,25 +148,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int height = source.Height; Rectangle destinationBounds = destination.Bounds(); - ParallelFor.WithConfiguration( - 0, - height, + ParallelHelper.IterateRows( + source.Bounds(), configuration, - y => - { - Span sourceRow = source.GetPixelRowSpan(y); - for (int x = 0; x < width; x++) + rows => { - int newX = height - y - 1; - newX = height - newX - 1; - int newY = width - x - 1; - - if (destinationBounds.Contains(newX, newY)) + for (int y = rows.Min; y < rows.Max; y++) { - destination[newX, newY] = sourceRow[x]; + Span sourceRow = source.GetPixelRowSpan(y); + for (int x = 0; x < width; x++) + { + int newX = height - y - 1; + newX = height - newX - 1; + int newY = width - x - 1; + + if (destinationBounds.Contains(newX, newY)) + { + destination[newX, newY] = sourceRow[x]; + } + } } - } - }); + }); } /// @@ -179,20 +182,22 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int width = source.Width; int height = source.Height; - ParallelFor.WithConfiguration( - 0, - height, + ParallelHelper.IterateRows( + source.Bounds(), configuration, - y => - { - Span sourceRow = source.GetPixelRowSpan(y); - Span targetRow = destination.GetPixelRowSpan(height - y - 1); - - for (int x = 0; x < width; x++) + rows => { - targetRow[width - x - 1] = sourceRow[x]; - } - }); + for (int y = rows.Min; y < rows.Max; y++) + { + Span sourceRow = source.GetPixelRowSpan(y); + Span targetRow = destination.GetPixelRowSpan(height - y - 1); + + for (int x = 0; x < width; x++) + { + targetRow[width - x - 1] = sourceRow[x]; + } + } + }); } /// @@ -207,22 +212,25 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms int height = source.Height; Rectangle destinationBounds = destination.Bounds(); - ParallelFor.WithConfiguration( - 0, - height, + ParallelHelper.IterateRows( + source.Bounds(), configuration, - y => - { - Span sourceRow = source.GetPixelRowSpan(y); - int newX = height - y - 1; - for (int x = 0; x < width; x++) + rows => { - if (destinationBounds.Contains(newX, x)) + for (int y = rows.Min; y < rows.Max; y++) { - destination[newX, x] = sourceRow[x]; + Span sourceRow = source.GetPixelRowSpan(y); + int newX = height - y - 1; + for (int x = 0; x < width; x++) + { + // TODO: Optimize this: + if (destinationBounds.Contains(newX, x)) + { + destination[newX, x] = sourceRow[x]; + } + } } - } - }); + }); } } } \ No newline at end of file From 5fd0979fefc15824f1f6283632f23001bb13a784 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:16:41 +0200 Subject: [PATCH 089/185] ParallelHelper -> ResizeProcessor --- .../Processors/Transforms/ResizeProcessor.cs | 148 ++++++++++-------- 1 file changed, 85 insertions(+), 63 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index fd3c34d6c1..aa4c3ada28 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -11,6 +11,7 @@ using System.Runtime.InteropServices; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -267,26 +268,31 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (this.Sampler is NearestNeighborResampler) { + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + // Scaling factors float widthFactor = sourceRectangle.Width / (float)this.ResizeRectangle.Width; float heightFactor = sourceRectangle.Height / (float)this.ResizeRectangle.Height; - ParallelFor.WithConfiguration( - minY, - maxY, + ParallelHelper.IterateRows( + workingRect, configuration, - y => - { - // Y coordinates of source points - Span sourceRow = source.GetPixelRowSpan((int)(((y - startY) * heightFactor) + sourceY)); - Span targetRow = destination.GetPixelRowSpan(y); - - for (int x = minX; x < maxX; x++) + rows => { - // X coordinates of source points - targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)]; - } - }); + for (int y = rows.Min; y < rows.Max; y++) + { + // Y coordinates of source points + Span sourceRow = + source.GetPixelRowSpan((int)(((y - startY) * heightFactor) + sourceY)); + Span targetRow = destination.GetPixelRowSpan(y); + + for (int x = minX; x < maxX; x++) + { + // X coordinates of source points + targetRow[x] = sourceRow[(int)(((x - startX) * widthFactor) + sourceX)]; + } + } + }); return; } @@ -300,72 +306,88 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { firstPassPixels.MemorySource.Clear(); - ParallelFor.WithTemporaryBuffer( - 0, - sourceRectangle.Bottom, + var processColsRect = new Rectangle(0, 0, source.Width, sourceRectangle.Bottom); + + ParallelHelper.IterateRowsWithTempBuffer( + processColsRect, configuration, - source.Width, - (int y, IMemoryOwner tempRowBuffer) => + (rows, tempRowBuffer) => { - ref Vector4 firstPassRow = ref MemoryMarshal.GetReference(firstPassPixels.GetRowSpan(y)); - Span sourceRow = source.GetPixelRowSpan(y); - Span tempRowSpan = tempRowBuffer.GetSpan(); + for (int y = rows.Min; y < rows.Max; y++) + { + ref Vector4 firstPassRow = + ref MemoryMarshal.GetReference(firstPassPixels.GetRowSpan(y)); + Span sourceRow = source.GetPixelRowSpan(y); + Span tempRowSpan = tempRowBuffer.Span; - PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length); + PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length); - if (this.Compand) - { - for (int x = minX; x < maxX; x++) + if (this.Compand) { - WeightsWindow window = this.horizontalWeights.Weights[x - startX]; - Unsafe.Add(ref firstPassRow, x) = window.ComputeExpandedWeightedRowSum(tempRowSpan, sourceX); + for (int x = minX; x < maxX; x++) + { + WeightsWindow window = this.horizontalWeights.Weights[x - startX]; + Unsafe.Add(ref firstPassRow, x) = + window.ComputeExpandedWeightedRowSum(tempRowSpan, sourceX); + } } - } - else - { - for (int x = minX; x < maxX; x++) + else { - WeightsWindow window = this.horizontalWeights.Weights[x - startX]; - Unsafe.Add(ref firstPassRow, x) = window.ComputeWeightedRowSum(tempRowSpan, sourceX); + for (int x = minX; x < maxX; x++) + { + WeightsWindow window = this.horizontalWeights.Weights[x - startX]; + Unsafe.Add(ref firstPassRow, x) = + window.ComputeWeightedRowSum(tempRowSpan, sourceX); + } } } }); + var processRowsRect = Rectangle.FromLTRB(0, minY, width, maxY); + // Now process the rows. - ParallelFor.WithConfiguration( - minY, - maxY, + ParallelHelper.IterateRows( + processRowsRect, configuration, - y => - { - // Ensure offsets are normalized for cropping and padding. - WeightsWindow window = this.verticalWeights.Weights[y - startY]; - ref TPixel targetRow = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - - if (this.Compand) - { - for (int x = 0; x < width; x++) - { - // Destination color components - Vector4 destinationVector = window.ComputeWeightedColumnSum(firstPassPixels, x, sourceY); - destinationVector = destinationVector.Compress(); - - ref TPixel pixel = ref Unsafe.Add(ref targetRow, x); - pixel.PackFromVector4(destinationVector); - } - } - else + rows => { - for (int x = 0; x < width; x++) + for (int y = rows.Min; y < rows.Max; y++) { - // Destination color components - Vector4 destinationVector = window.ComputeWeightedColumnSum(firstPassPixels, x, sourceY); + // Ensure offsets are normalized for cropping and padding. + WeightsWindow window = this.verticalWeights.Weights[y - startY]; + ref TPixel targetRow = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - ref TPixel pixel = ref Unsafe.Add(ref targetRow, x); - pixel.PackFromVector4(destinationVector); + if (this.Compand) + { + for (int x = 0; x < width; x++) + { + // Destination color components + Vector4 destinationVector = window.ComputeWeightedColumnSum( + firstPassPixels, + x, + sourceY); + destinationVector = destinationVector.Compress(); + + ref TPixel pixel = ref Unsafe.Add(ref targetRow, x); + pixel.PackFromVector4(destinationVector); + } + } + else + { + for (int x = 0; x < width; x++) + { + // Destination color components + Vector4 destinationVector = window.ComputeWeightedColumnSum( + firstPassPixels, + x, + sourceY); + + ref TPixel pixel = ref Unsafe.Add(ref targetRow, x); + pixel.PackFromVector4(destinationVector); + } + } } - } - }); + }); } } From 7277ca2a29115688b38ac541ea22711b05c7caec Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:30:22 +0200 Subject: [PATCH 090/185] DrawImageProcessor + formatting --- .../Processors/Drawing/DrawImageProcessor.cs | 178 ++++++------ .../Processors/Drawing/FillProcessor.cs | 214 +++++++-------- .../Drawing/FillPatternTests.cs | 255 +++++++++++------- .../Drawing/FillSolidBrushTests.cs | 44 +-- 4 files changed, 379 insertions(+), 312 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index 4e6018e07a..add34ca36c 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -1,95 +1,101 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Drawing -{ - /// - /// Combines two images together by blending the pixels. - /// +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Drawing +{ + /// + /// Combines two images together by blending the pixels. + /// /// The pixel format of destination image. - /// The pixel format os source image. - internal class DrawImageProcessor : ImageProcessor + /// The pixel format os source image. + internal class DrawImageProcessor : ImageProcessor where TPixelDst : struct, IPixel - where TPixelSrc : struct, IPixel + where TPixelSrc : struct, IPixel { - /// - /// Initializes a new instance of the class. - /// - /// The image to blend with the currently processing image. + /// + /// Initializes a new instance of the class. + /// + /// The image to blend with the currently processing image. /// The location to draw the blended image. /// The blending mode to use when drawing the image. /// The Alpha blending mode to use when drawing the image. - /// The opacity of the image to blend. Must be between 0 and 1. - public DrawImageProcessor(Image image, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity) - { - Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); - - this.Image = image; - this.Opacity = opacity; - this.Blender = PixelOperations.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); - this.Location = location; - } - - /// - /// Gets the image to blend - /// - public Image Image { get; } - - /// - /// Gets the opacity of the image to blend - /// - public float Opacity { get; } - - /// - /// Gets the pixel blender - /// - public PixelBlender Blender { get; } - - /// - /// Gets the location to draw the blended image - /// - public Point Location { get; } - - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - Image targetImage = this.Image; - PixelBlender blender = this.Blender; - int locationY = this.Location.Y; - - // Align start/end positions. - Rectangle bounds = targetImage.Bounds(); - - int minX = Math.Max(this.Location.X, sourceRectangle.X); - int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); - int targetX = minX - this.Location.X; - - int minY = Math.Max(this.Location.Y, sourceRectangle.Y); - int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); - - int width = maxX - minX; - + /// The opacity of the image to blend. Must be between 0 and 1. + public DrawImageProcessor(Image image, Point location, PixelColorBlendingMode colorBlendingMode, PixelAlphaCompositionMode alphaCompositionMode, float opacity) + { + Guard.MustBeBetweenOrEqualTo(opacity, 0, 1, nameof(opacity)); + + this.Image = image; + this.Opacity = opacity; + this.Blender = PixelOperations.Instance.GetPixelBlender(colorBlendingMode, alphaCompositionMode); + this.Location = location; + } + + /// + /// Gets the image to blend + /// + public Image Image { get; } + + /// + /// Gets the opacity of the image to blend + /// + public float Opacity { get; } + + /// + /// Gets the pixel blender + /// + public PixelBlender Blender { get; } + + /// + /// Gets the location to draw the blended image + /// + public Point Location { get; } + + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + Image targetImage = this.Image; + PixelBlender blender = this.Blender; + int locationY = this.Location.Y; + + // Align start/end positions. + Rectangle bounds = targetImage.Bounds(); + + int minX = Math.Max(this.Location.X, sourceRectangle.X); + int maxX = Math.Min(this.Location.X + bounds.Width, sourceRectangle.Width); + int targetX = minX - this.Location.X; + + int minY = Math.Max(this.Location.Y, sourceRectangle.Y); + int maxY = Math.Min(this.Location.Y + bounds.Height, sourceRectangle.Bottom); + + int width = maxX - minX; + MemoryAllocator memoryAllocator = this.Image.GetConfiguration().MemoryAllocator; - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - Span background = source.GetPixelRowSpan(y).Slice(minX, width); - Span foreground = targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); - blender.Blend(memoryAllocator, background, background, foreground, this.Opacity); - }); - } - } + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + + ParallelHelper.IterateRows( + workingRect, + configuration, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span background = source.GetPixelRowSpan(y).Slice(minX, width); + Span foreground = + targetImage.GetPixelRowSpan(y - locationY).Slice(targetX, width); + blender.Blend(memoryAllocator, background, background, foreground, this.Opacity); + } + }); + } + } } \ No newline at end of file diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs index 3285e75a7b..4f2be309b0 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -1,107 +1,107 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Buffers; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.Memory; -using SixLabors.Primitives; - -namespace SixLabors.ImageSharp.Processing.Processors.Drawing -{ - /// - /// Using the brush as a source of pixels colors blends the brush color with source. - /// - /// The pixel format. - internal class FillProcessor : ImageProcessor - where TPixel : struct, IPixel - { - /// - /// The brush. - /// - private readonly IBrush brush; - private readonly GraphicsOptions options; - - /// - /// Initializes a new instance of the class. - /// - /// The brush to source pixel colors from. - /// The options - public FillProcessor(IBrush brush, GraphicsOptions options) - { - this.brush = brush; - this.options = options; - } - - /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - - // Align start/end positions. - int minX = Math.Max(0, startX); - int maxX = Math.Min(source.Width, endX); - int minY = Math.Max(0, startY); - int maxY = Math.Min(source.Height, endY); - - int width = maxX - minX; - - // If there's no reason for blending, then avoid it. - if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) - { - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); - }); - } - else - { - // Reset offset if necessary. - if (minX > 0) - { - startX = 0; - } - - if (minY > 0) - { - startY = 0; - } - - using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) - using (BrushApplicator applicator = this.brush.CreateApplicator( - source, - sourceRectangle, - this.options)) - { - amount.GetSpan().Fill(1f); - - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - int offsetY = y - startY; - int offsetX = minX - startX; - - applicator.Apply(amount.GetSpan(), offsetX, offsetY); - }); - } - } - } - - private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) - { +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers; +using System.Threading.Tasks; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.Memory; +using SixLabors.Primitives; + +namespace SixLabors.ImageSharp.Processing.Processors.Drawing +{ + /// + /// Using the brush as a source of pixels colors blends the brush color with source. + /// + /// The pixel format. + internal class FillProcessor : ImageProcessor + where TPixel : struct, IPixel + { + /// + /// The brush. + /// + private readonly IBrush brush; + private readonly GraphicsOptions options; + + /// + /// Initializes a new instance of the class. + /// + /// The brush to source pixel colors from. + /// The options + public FillProcessor(IBrush brush, GraphicsOptions options) + { + this.brush = brush; + this.options = options; + } + + /// + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) + { + int startX = sourceRectangle.X; + int endX = sourceRectangle.Right; + int startY = sourceRectangle.Y; + int endY = sourceRectangle.Bottom; + + // Align start/end positions. + int minX = Math.Max(0, startX); + int maxX = Math.Min(source.Width, endX); + int minY = Math.Max(0, startY); + int maxY = Math.Min(source.Height, endY); + + int width = maxX - minX; + + // If there's no reason for blending, then avoid it. + if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) + { + ParallelFor.WithConfiguration( + minY, + maxY, + configuration, + y => + { + source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); + }); + } + else + { + // Reset offset if necessary. + if (minX > 0) + { + startX = 0; + } + + if (minY > 0) + { + startY = 0; + } + + using (IMemoryOwner amount = source.MemoryAllocator.Allocate(width)) + using (BrushApplicator applicator = this.brush.CreateApplicator( + source, + sourceRectangle, + this.options)) + { + amount.GetSpan().Fill(1f); + + ParallelFor.WithConfiguration( + minY, + maxY, + configuration, + y => + { + int offsetY = y - startY; + int offsetX = minX - startX; + + applicator.Apply(amount.GetSpan(), offsetX, offsetY); + }); + } + } + } + + private bool IsSolidBrushWithoutBlending(out SolidBrush solidBrush) + { solidBrush = this.brush as SolidBrush; if (solidBrush == null) @@ -109,7 +109,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing return false; } - return this.options.IsOpaqueColorWithoutBlending(solidBrush.Color); - } - } + return this.options.IsOpaqueColorWithoutBlending(solidBrush.Color); + } + } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs b/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs index 93715c586e..b310c7afc6 100644 --- a/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillPatternTests.cs @@ -54,172 +54,225 @@ namespace SixLabors.ImageSharp.Tests.Drawing [Fact] public void ImageShouldBeFloodFilledWithPercent10() { - this.Test("Percent10", Rgba32.Blue, Brushes.Percent10(Rgba32.HotPink, Rgba32.LimeGreen), + this.Test( + "Percent10", + Rgba32.Blue, + Brushes.Percent10(Rgba32.HotPink, Rgba32.LimeGreen), new[,] - { - { Rgba32.HotPink , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink , Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen} - }); + { + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithPercent10Transparent() { - Test("Percent10_Transparent", Rgba32.Blue, Brushes.Percent10(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.HotPink , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink , Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue} - }); + this.Test( + "Percent10_Transparent", + Rgba32.Blue, + Brushes.Percent10(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue } + }); } [Fact] public void ImageShouldBeFloodFilledWithPercent20() { - Test("Percent20", Rgba32.Blue, Brushes.Percent20(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.HotPink , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink , Rgba32.LimeGreen}, - { Rgba32.HotPink , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink , Rgba32.LimeGreen} - }); + this.Test( + "Percent20", + Rgba32.Blue, + Brushes.Percent20(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen }, + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithPercent20_transparent() { - Test("Percent20_Transparent", Rgba32.Blue, Brushes.Percent20(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.HotPink , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink , Rgba32.Blue}, - { Rgba32.HotPink , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink , Rgba32.Blue} - }); + this.Test( + "Percent20_Transparent", + Rgba32.Blue, + Brushes.Percent20(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue }, + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue } + }); } [Fact] public void ImageShouldBeFloodFilledWithHorizontal() { - Test("Horizontal", Rgba32.Blue, Brushes.Horizontal(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.LimeGreen , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink , Rgba32.HotPink}, - { Rgba32.LimeGreen , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen , Rgba32.LimeGreen} - }); + this.Test( + "Horizontal", + Rgba32.Blue, + Brushes.Horizontal(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithHorizontal_transparent() { - Test("Horizontal_Transparent", Rgba32.Blue, Brushes.Horizontal(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.Blue , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink , Rgba32.HotPink}, - { Rgba32.Blue , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue , Rgba32.Blue} - }); + this.Test( + "Horizontal_Transparent", + Rgba32.Blue, + Brushes.Horizontal(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue } + }); } - - [Fact] public void ImageShouldBeFloodFilledWithMin() { - Test("Min", Rgba32.Blue, Brushes.Min(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.LimeGreen , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen , Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen , Rgba32.LimeGreen}, - { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink , Rgba32.HotPink} - }); + this.Test( + "Min", + Rgba32.Blue, + Brushes.Min(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink } + }); } [Fact] public void ImageShouldBeFloodFilledWithMin_transparent() { - Test("Min_Transparent", Rgba32.Blue, Brushes.Min(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.Blue , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue , Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue , Rgba32.Blue}, - { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink , Rgba32.HotPink}, - }); + this.Test( + "Min_Transparent", + Rgba32.Blue, + Brushes.Min(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink, Rgba32.HotPink }, + }); } [Fact] public void ImageShouldBeFloodFilledWithVertical() { - Test("Vertical", Rgba32.Blue, Brushes.Vertical(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen} - }); + this.Test( + "Vertical", + Rgba32.Blue, + Brushes.Vertical(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithVertical_transparent() { - Test("Vertical_Transparent", Rgba32.Blue, Brushes.Vertical(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue} - }); + this.Test( + "Vertical_Transparent", + Rgba32.Blue, + Brushes.Vertical(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue } + }); } [Fact] public void ImageShouldBeFloodFilledWithForwardDiagonal() { - Test("ForwardDiagonal", Rgba32.Blue, Brushes.ForwardDiagonal(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen} - }); + this.Test( + "ForwardDiagonal", + Rgba32.Blue, + Brushes.ForwardDiagonal(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen } + }); } [Fact] public void ImageShouldBeFloodFilledWithForwardDiagonal_transparent() { - Test("ForwardDiagonal_Transparent", Rgba32.Blue, Brushes.ForwardDiagonal(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue} - }); + this.Test( + "ForwardDiagonal_Transparent", + Rgba32.Blue, + Brushes.ForwardDiagonal(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue } + }); } [Fact] public void ImageShouldBeFloodFilledWithBackwardDiagonal() { - Test("BackwardDiagonal", Rgba32.Blue, Brushes.BackwardDiagonal(Rgba32.HotPink, Rgba32.LimeGreen), - new Rgba32[,] { - { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen}, - { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink} - }); + this.Test( + "BackwardDiagonal", + Rgba32.Blue, + Brushes.BackwardDiagonal(Rgba32.HotPink, Rgba32.LimeGreen), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink, Rgba32.LimeGreen }, + { Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.LimeGreen, Rgba32.HotPink } + }); } [Fact] public void ImageShouldBeFloodFilledWithBackwardDiagonal_transparent() { - Test("BackwardDiagonal_Transparent", Rgba32.Blue, Brushes.BackwardDiagonal(Rgba32.HotPink), - new Rgba32[,] { - { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue}, - { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink} - }); + this.Test( + "BackwardDiagonal_Transparent", + Rgba32.Blue, + Brushes.BackwardDiagonal(Rgba32.HotPink), + new Rgba32[,] + { + { Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink, Rgba32.Blue }, + { Rgba32.Blue, Rgba32.Blue, Rgba32.Blue, Rgba32.HotPink } + }); } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs index e86d41f574..32f723e72a 100644 --- a/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillSolidBrushTests.cs @@ -1,20 +1,21 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; + using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Primitives; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; +using SixLabors.Primitives; using SixLabors.Shapes; + using Xunit; + // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Drawing { - using System; - - using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; - using SixLabors.Primitives; - [GroupOutput("Drawing")] public class FillSolidBrushTests { @@ -55,7 +56,9 @@ namespace SixLabors.ImageSharp.Tests.Drawing [Theory] [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, "Blue")] [WithSolidFilledImages(16, 16, "Yellow", PixelTypes.Rgba32, "Khaki")] - public void WhenColorIsOpaque_OverridePreviousColor(TestImageProvider provider, string newColorName) + public void WhenColorIsOpaque_OverridePreviousColor( + TestImageProvider provider, + string newColorName) where TPixel : struct, IPixel { using (Image image = provider.GetImage()) @@ -63,7 +66,11 @@ namespace SixLabors.ImageSharp.Tests.Drawing TPixel color = TestUtils.GetPixelOfNamedColor(newColorName); image.Mutate(c => c.Fill(color)); - image.DebugSave(provider, newColorName, appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); + image.DebugSave( + provider, + newColorName, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); image.ComparePixelBufferTo(color); } } @@ -84,7 +91,12 @@ namespace SixLabors.ImageSharp.Tests.Drawing [Theory] [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 5, 7, 3, 8)] [WithSolidFilledImages(16, 16, "Red", PixelTypes.Rgba32, 8, 5, 6, 4)] - public void FillRegion_WorksOnWrappedMemoryImage(TestImageProvider provider, int x0, int y0, int w, int h) + public void FillRegion_WorksOnWrappedMemoryImage( + TestImageProvider provider, + int x0, + int y0, + int w, + int h) where TPixel : struct, IPixel { FormattableString testDetails = $"(x{x0},y{y0},w{w},h{h})"; @@ -105,27 +117,22 @@ namespace SixLabors.ImageSharp.Tests.Drawing { false, "Blue", 1.0f, PixelColorBlendingMode.Normal, 0.5f }, { false, "Green", 0.5f, PixelColorBlendingMode.Normal, 0.3f }, { false, "HotPink", 0.8f, PixelColorBlendingMode.Normal, 0.8f }, - { false, "Blue", 0.5f, PixelColorBlendingMode.Multiply, 1.0f }, { false, "Blue", 1.0f, PixelColorBlendingMode.Multiply, 0.5f }, { false, "Green", 0.5f, PixelColorBlendingMode.Multiply, 0.3f }, { false, "HotPink", 0.8f, PixelColorBlendingMode.Multiply, 0.8f }, - { false, "Blue", 0.5f, PixelColorBlendingMode.Add, 1.0f }, { false, "Blue", 1.0f, PixelColorBlendingMode.Add, 0.5f }, { false, "Green", 0.5f, PixelColorBlendingMode.Add, 0.3f }, { false, "HotPink", 0.8f, PixelColorBlendingMode.Add, 0.8f }, - { true, "Blue", 0.5f, PixelColorBlendingMode.Normal, 1.0f }, { true, "Blue", 1.0f, PixelColorBlendingMode.Normal, 0.5f }, { true, "Green", 0.5f, PixelColorBlendingMode.Normal, 0.3f }, { true, "HotPink", 0.8f, PixelColorBlendingMode.Normal, 0.8f }, - { true, "Blue", 0.5f, PixelColorBlendingMode.Multiply, 1.0f }, { true, "Blue", 1.0f, PixelColorBlendingMode.Multiply, 0.5f }, { true, "Green", 0.5f, PixelColorBlendingMode.Multiply, 0.3f }, { true, "HotPink", 0.8f, PixelColorBlendingMode.Multiply, 0.8f }, - { true, "Blue", 0.5f, PixelColorBlendingMode.Add, 1.0f }, { true, "Blue", 1.0f, PixelColorBlendingMode.Add, 0.5f }, { true, "Green", 0.5f, PixelColorBlendingMode.Add, 0.3f }, @@ -155,8 +162,7 @@ namespace SixLabors.ImageSharp.Tests.Drawing var options = new GraphicsOptions(false) { - ColorBlendingMode = blenderMode, - BlendPercentage = blendPercentage + ColorBlendingMode = blenderMode, BlendPercentage = blendPercentage }; if (triggerFillRegion) @@ -185,11 +191,13 @@ namespace SixLabors.ImageSharp.Tests.Drawing appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); - PixelBlender blender = PixelOperations.Instance.GetPixelBlender(blenderMode, PixelAlphaCompositionMode.SrcOver); + PixelBlender blender = PixelOperations.Instance.GetPixelBlender( + blenderMode, + PixelAlphaCompositionMode.SrcOver); TPixel expectedPixel = blender.Blend(bgColor, fillColor, blendPercentage); image.ComparePixelBufferTo(expectedPixel); } } } -} +} \ No newline at end of file From 4da33609f844c47a286a3b495ddab1c9cc10e2b5 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:35:40 +0200 Subject: [PATCH 091/185] ParallelHelper -> FillProcessor --- .../Processors/Drawing/FillProcessor.cs | 39 ++++++++++++------- 1 file changed, 24 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs index 4f2be309b0..ed6c869511 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/FillProcessor.cs @@ -6,6 +6,7 @@ using System.Buffers; using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -52,17 +53,23 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing int width = maxX - minX; + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + // If there's no reason for blending, then avoid it. if (this.IsSolidBrushWithoutBlending(out SolidBrush solidBrush)) { - ParallelFor.WithConfiguration( - minY, - maxY, - configuration, - y => - { - source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); - }); + ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings().MultiplyMinimumPixelsPerTask(4); + + ParallelHelper.IterateRows( + workingRect, + parallelSettings, + rows => + { + for (int y = rows.Min; y < rows.Max; y++) + { + source.GetPixelRowSpan(y).Slice(minX, width).Fill(solidBrush.Color); + } + }); } else { @@ -85,16 +92,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing { amount.GetSpan().Fill(1f); - ParallelFor.WithConfiguration( - minY, - maxY, + ParallelHelper.IterateRows( + workingRect, configuration, - y => + rows => { - int offsetY = y - startY; - int offsetX = minX - startX; + for (int y = rows.Min; y < rows.Max; y++) + { + int offsetY = y - startY; + int offsetX = minX - startX; - applicator.Apply(amount.GetSpan(), offsetX, offsetY); + applicator.Apply(amount.GetSpan(), offsetX, offsetY); + } }); } } From a446f1bee2c6487690e3165389cd705a87cdf891 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:43:02 +0200 Subject: [PATCH 092/185] ParallelHelper -> CloneAs() + drop ParallelFor --- src/ImageSharp/Common/Helpers/ParallelFor.cs | 62 ---------- src/ImageSharp/ImageFrame{TPixel}.cs | 31 +++-- .../Codecs/CopyPixels.cs | 115 ------------------ tests/ImageSharp.Benchmarks/Samplers/Glow.cs | 38 +++--- 4 files changed, 39 insertions(+), 207 deletions(-) delete mode 100644 src/ImageSharp/Common/Helpers/ParallelFor.cs delete mode 100644 tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs diff --git a/src/ImageSharp/Common/Helpers/ParallelFor.cs b/src/ImageSharp/Common/Helpers/ParallelFor.cs deleted file mode 100644 index 191875a950..0000000000 --- a/src/ImageSharp/Common/Helpers/ParallelFor.cs +++ /dev/null @@ -1,62 +0,0 @@ -using System; -using System.Buffers; -using System.Threading.Tasks; - -using SixLabors.Memory; - -namespace SixLabors.ImageSharp -{ - /// - /// Utility methods for Parallel.For() execution. Use this instead of raw calls! - /// - internal static class ParallelFor - { - /// - /// Helper method to execute Parallel.For using the settings in - /// - public static void WithConfiguration(int fromInclusive, int toExclusive, Configuration configuration, Action body) - { - Parallel.For(fromInclusive, toExclusive, configuration.GetParallelOptions(), body); - } - - /// - /// Helper method to execute Parallel.For with temporary worker buffer shared between executing tasks. - /// The buffer is not guaranteed to be clean! - /// - /// The value type of the buffer - /// The start index, inclusive. - /// The end index, exclusive. - /// The used for getting the and - /// The length of the requested parallel buffer - /// The delegate that is invoked once per iteration. - public static void WithTemporaryBuffer( - int fromInclusive, - int toExclusive, - Configuration configuration, - int bufferLength, - Action> body) - where T : struct - { - MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - ParallelOptions parallelOptions = configuration.GetParallelOptions(); - - IMemoryOwner InitBuffer() - { - return memoryAllocator.Allocate(bufferLength); - } - - void CleanUpBuffer(IMemoryOwner buffer) - { - buffer.Dispose(); - } - - IMemoryOwner BodyFunc(int i, ParallelLoopState state, IMemoryOwner buffer) - { - body(i, buffer); - return buffer; - } - - Parallel.For(fromInclusive, toExclusive, parallelOptions, InitBuffer, BodyFunc, CleanUpBuffer); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 132ab598e5..511e8ad687 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.MetaData; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; using SixLabors.Primitives; @@ -262,20 +263,24 @@ namespace SixLabors.ImageSharp var target = new ImageFrame(this.configuration, this.Width, this.Height, this.MetaData.Clone()); - ParallelFor.WithTemporaryBuffer( - 0, - this.Height, + ParallelHelper.IterateRowsWithTempBuffer( + this.Bounds(), this.configuration, - this.Width, - (int y, IMemoryOwner tempRowBuffer) => - { - Span sourceRow = this.GetPixelRowSpan(y); - Span targetRow = target.GetPixelRowSpan(y); - Span tempRowSpan = tempRowBuffer.GetSpan(); - - PixelOperations.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length); - PixelOperations.Instance.PackFromScaledVector4(tempRowSpan, targetRow, targetRow.Length); - }); + (rows, tempRowBuffer) => + { + for (int y = rows.Min; y < rows.Max; y++) + { + Span sourceRow = this.GetPixelRowSpan(y); + Span targetRow = target.GetPixelRowSpan(y); + Span tempRowSpan = tempRowBuffer.Span; + + PixelOperations.Instance.ToScaledVector4(sourceRow, tempRowSpan, sourceRow.Length); + PixelOperations.Instance.PackFromScaledVector4( + tempRowSpan, + targetRow, + targetRow.Length); + } + }); return target; } diff --git a/tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs b/tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs deleted file mode 100644 index d55c231a73..0000000000 --- a/tests/ImageSharp.Benchmarks/Codecs/CopyPixels.cs +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Threading.Tasks; - -using BenchmarkDotNet.Attributes; - -using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Memory; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Benchmarks.Codecs -{ - public class CopyPixels : BenchmarkBase - { - [Benchmark(Baseline = true, Description = "PixelAccessor Copy by indexer")] - public Rgba32 CopyByPixelAccesor() - { - using (var source = new Image(1024, 768)) - using (var target = new Image(1024, 768)) - { - Buffer2D sourcePixels = source.GetRootFramePixelBuffer(); - Buffer2D targetPixels = target.GetRootFramePixelBuffer(); - ParallelFor.WithConfiguration( - 0, - source.Height, - Configuration.Default, - y => - { - for (int x = 0; x < source.Width; x++) - { - targetPixels[x, y] = sourcePixels[x, y]; - } - }); - - return targetPixels[0, 0]; - } - } - - [Benchmark(Description = "PixelAccessor Copy by Span")] - public Rgba32 CopyByPixelAccesorSpan() - { - using (var source = new Image(1024, 768)) - using (var target = new Image(1024, 768)) - { - Buffer2D sourcePixels = source.GetRootFramePixelBuffer(); - Buffer2D targetPixels = target.GetRootFramePixelBuffer(); - ParallelFor.WithConfiguration( - 0, - source.Height, - Configuration.Default, - y => - { - Span sourceRow = sourcePixels.GetRowSpan(y); - Span targetRow = targetPixels.GetRowSpan(y); - - for (int x = 0; x < source.Width; x++) - { - targetRow[x] = sourceRow[x]; - } - }); - - return targetPixels[0, 0]; - } - } - - [Benchmark(Description = "Copy by indexer")] - public Rgba32 Copy() - { - using (var source = new Image(1024, 768)) - using (var target = new Image(1024, 768)) - { - ParallelFor.WithConfiguration( - 0, - source.Height, - Configuration.Default, - y => - { - for (int x = 0; x < source.Width; x++) - { - target[x, y] = source[x, y]; - } - }); - - return target[0, 0]; - } - } - - [Benchmark(Description = "Copy by Span")] - public Rgba32 CopySpan() - { - using (var source = new Image(1024, 768)) - using (var target = new Image(1024, 768)) - { - ParallelFor.WithConfiguration( - 0, - source.Height, - Configuration.Default, - y => - { - Span sourceRow = source.Frames.RootFrame.GetPixelRowSpan(y); - Span targetRow = target.Frames.RootFrame.GetPixelRowSpan(y); - - for (int x = 0; x < source.Width; x++) - { - targetRow[x] = sourceRow[x]; - } - }); - - return target[0, 0]; - } - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs index fe1d4221d1..ff2e57b974 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Glow.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Glow.cs @@ -9,6 +9,7 @@ using System.Threading.Tasks; using BenchmarkDotNet.Attributes; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors; using SixLabors.ImageSharp.Processing.Processors.Overlays; @@ -112,26 +113,29 @@ namespace SixLabors.ImageSharp.Benchmarks Buffer2D sourcePixels = source.PixelBuffer; rowColors.GetSpan().Fill(glowColor); - ParallelFor.WithConfiguration( - minY, - maxY, + var workingRect = Rectangle.FromLTRB(minX, minY, maxX, maxY); + ParallelHelper.IterateRows( + workingRect, configuration, - y => + rows => { - int offsetY = y - startY; - - for (int x = minX; x < maxX; x++) + for (int y = rows.Min; y < rows.Max; y++) { - int offsetX = x - startX; - float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); - Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); - TPixel packed = default(TPixel); - packed.PackFromVector4( - PremultipliedLerp( - sourceColor, - glowColor.ToVector4(), - 1 - (.95F * (distance / maxDistance)))); - sourcePixels[offsetX, offsetY] = packed; + int offsetY = y - startY; + + for (int x = minX; x < maxX; x++) + { + int offsetX = x - startX; + float distance = Vector2.Distance(centre, new Vector2(offsetX, offsetY)); + Vector4 sourceColor = sourcePixels[offsetX, offsetY].ToVector4(); + TPixel packed = default(TPixel); + packed.PackFromVector4( + PremultipliedLerp( + sourceColor, + glowColor.ToVector4(), + 1 - (.95F * (distance / maxDistance)))); + sourcePixels[offsetX, offsetY] = packed; + } } }); } From d63d08a9ac08fa590db9edbabb561c1f6511af9b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 01:56:05 +0200 Subject: [PATCH 093/185] optimize ImageFrame.Clear() --- src/ImageSharp/ImageFrame{TPixel}.cs | 19 ++++++++++--------- .../Processors/Overlays/GlowProcessor.cs | 1 - 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/ImageFrame{TPixel}.cs b/src/ImageSharp/ImageFrame{TPixel}.cs index 92470e2543..be1792ced1 100644 --- a/src/ImageSharp/ImageFrame{TPixel}.cs +++ b/src/ImageSharp/ImageFrame{TPixel}.cs @@ -318,15 +318,16 @@ namespace SixLabors.ImageSharp /// The value to initialize the bitmap with. internal void Clear(ParallelOptions parallelOptions, TPixel value) { - Parallel.For( - 0, - this.Height, - parallelOptions, - y => - { - Span targetRow = this.GetPixelRowSpan(y); - targetRow.Fill(value); - }); + Span span = this.GetPixelSpan(); + + if (value.Equals(default)) + { + span.Clear(); + } + else + { + span.Fill(value); + } } /// diff --git a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs index d774a10ab8..93d6edff19 100644 --- a/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Overlays/GlowProcessor.cs @@ -86,7 +86,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Overlays protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { // TODO: can we simplify the rectangle calculation? - int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; From c84cb48ba53e635043216aeec085435a0248d533 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 02:01:24 +0200 Subject: [PATCH 094/185] cleanup & docs --- .../ParallelUtils/ParallelExecutionSettings.cs | 13 +++++++++++++ .../Common/ParallelUtils/ParallelHelper.cs | 10 ++++------ src/ImageSharp/Memory/RowInterval.cs | 3 +++ 3 files changed, 20 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs index 9b2ae89d0a..dc24383146 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs @@ -17,6 +17,9 @@ namespace SixLabors.ImageSharp.ParallelUtils /// public const int DefaultMinimumPixelsProcessedPerTask = 4096; + /// + /// Initializes a new instance of the struct. + /// public ParallelExecutionSettings( int maxDegreeOfParallelism, int minimumPixelsProcessedPerTask, @@ -27,11 +30,17 @@ namespace SixLabors.ImageSharp.ParallelUtils this.MemoryAllocator = memoryAllocator; } + /// + /// Initializes a new instance of the struct. + /// public ParallelExecutionSettings(int maxDegreeOfParallelism, MemoryAllocator memoryAllocator) : this(maxDegreeOfParallelism, DefaultMinimumPixelsProcessedPerTask, memoryAllocator) { } + /// + /// Gets the MemoryAllocator + /// public MemoryAllocator MemoryAllocator { get; } /// @@ -46,6 +55,10 @@ namespace SixLabors.ImageSharp.ParallelUtils /// public int MinimumPixelsProcessedPerTask { get; } + /// + /// Creates a new instance of + /// having multiplied by + /// public ParallelExecutionSettings MultiplyMinimumPixelsPerTask(int multiplier) { return new ParallelExecutionSettings( diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs index 3009e99fc4..1f999cfd2b 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs @@ -127,6 +127,10 @@ namespace SixLabors.ImageSharp.ParallelUtils }); } + /// + /// Iterate through the rows of a rectangle in optimized batches defined by -s + /// instantiating a temporary buffer for each invocation. + /// public static void IterateRowsWithTempBuffer( Rectangle rectangle, Configuration configuration, @@ -143,11 +147,5 @@ namespace SixLabors.ImageSharp.ParallelUtils int result = dividend / divisor; return dividend % divisor == 0 ? result : result + 1; } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int DivideRound(int dividend, int divisor) - { - return (dividend + (divisor / 2)) / divisor; - } } } \ No newline at end of file diff --git a/src/ImageSharp/Memory/RowInterval.cs b/src/ImageSharp/Memory/RowInterval.cs index 273a6aa346..0750e0368c 100644 --- a/src/ImageSharp/Memory/RowInterval.cs +++ b/src/ImageSharp/Memory/RowInterval.cs @@ -10,6 +10,9 @@ namespace SixLabors.ImageSharp.Memory /// internal readonly struct RowInterval { + /// + /// Initializes a new instance of the struct. + /// public RowInterval(int min, int max) { DebugGuard.MustBeLessThan(min, max, nameof(min)); From 0e443beeec28f7935a6928ef5ee3dc085c1f867a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 17:41:15 +0200 Subject: [PATCH 095/185] make ParallelExecutionSettings a readonly struct --- .../Common/ParallelUtils/ParallelExecutionSettings.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs index dc24383146..0b45719c38 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelExecutionSettings.cs @@ -10,7 +10,7 @@ namespace SixLabors.ImageSharp.ParallelUtils /// /// Defines execution settings for methods in . /// - internal struct ParallelExecutionSettings + internal readonly struct ParallelExecutionSettings { /// /// Default value for . @@ -51,7 +51,8 @@ namespace SixLabors.ImageSharp.ParallelUtils /// /// Gets the minimum number of pixels being processed by a single task when parallelizing operations with TPL. /// Launching tasks for pixel regions below this limit is not worth the overhead. - /// Initialized with 2048 by default, the optimum value is operation specific. + /// Initialized with by default, + /// the optimum value is operation specific. (The cheaper the operation, the larger the value is.) /// public int MinimumPixelsProcessedPerTask { get; } From 20ff3ab0a1d6de40d877361f64f8b65f9b84a409 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 23 Sep 2018 20:55:34 +0200 Subject: [PATCH 096/185] fix typo, improve DivideCeil --- .../Processing/Processors/Drawing/DrawImageProcessor.cs | 2 +- src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs | 7 +------ 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs index add34ca36c..dc73420f30 100644 --- a/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs +++ b/src/ImageSharp.Drawing/Processing/Processors/Drawing/DrawImageProcessor.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Drawing /// Combines two images together by blending the pixels. /// /// The pixel format of destination image. - /// The pixel format os source image. + /// The pixel format of source image. internal class DrawImageProcessor : ImageProcessor where TPixelDst : struct, IPixel where TPixelSrc : struct, IPixel diff --git a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs index 1f999cfd2b..1d1734a863 100644 --- a/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs +++ b/src/ImageSharp/Common/ParallelUtils/ParallelHelper.cs @@ -141,11 +141,6 @@ namespace SixLabors.ImageSharp.ParallelUtils } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int DivideCeil(int dividend, int divisor) - { - // TODO: Is there a more efficient way to calculate this? - int result = dividend / divisor; - return dividend % divisor == 0 ? result : result + 1; - } + private static int DivideCeil(int dividend, int divisor) => 1 + ((dividend - 1) / divisor); } } \ No newline at end of file From fcbe2ba2895292ef47ed2bffdc17d45fac000f48 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Sep 2018 00:38:06 +0100 Subject: [PATCH 097/185] Add scale down from 8bit method This nearly works... Scaling seems correct but getting an unexpected offset. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 18 +++-- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 71 +++++++++++++++---- .../Quantization/QuantizedFrame{TPixel}.cs | 8 +++ 3 files changed, 78 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index ef2f226556..c52f974944 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -92,6 +92,11 @@ namespace SixLabors.ImageSharp.Formats.Png /// private readonly bool ignoreMetadata; + /// + /// Used the manage memory allocations. + /// + private readonly MemoryAllocator memoryAllocator; + /// /// The stream to decode from. /// @@ -200,12 +205,11 @@ namespace SixLabors.ImageSharp.Formats.Png public PngDecoderCore(Configuration configuration, IPngDecoderOptions options) { this.configuration = configuration ?? Configuration.Default; + this.memoryAllocator = this.configuration.MemoryAllocator; this.textEncoding = options.TextEncoding ?? PngConstants.DefaultEncoding; this.ignoreMetadata = options.IgnoreMetadata; } - private MemoryAllocator MemoryAllocator => this.configuration.MemoryAllocator; - /// /// Decodes the stream to the image. /// @@ -391,12 +395,12 @@ namespace SixLabors.ImageSharp.Formats.Png return false; } - buffer = this.MemoryAllocator.AllocateManagedByteBuffer(bytesPerScanline * 8 / bits, AllocationOptions.Clean); + buffer = this.memoryAllocator.AllocateManagedByteBuffer(bytesPerScanline * 8 / bits, AllocationOptions.Clean); byte[] result = buffer.Array; int mask = 0xFF >> (8 - bits); int resultOffset = 0; - for (int i = 0; i < bytesPerScanline - 1; i++) + for (int i = 0; i < bytesPerScanline; i++) { byte b = source[i]; for (int shift = 0; shift < 8; shift += bits) @@ -470,7 +474,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.bytesPerSample = this.header.BitDepth / 8; } - this.previousScanline = this.MemoryAllocator.AllocateManagedByteBuffer(this.bytesPerScanline, AllocationOptions.Clean); + this.previousScanline = this.memoryAllocator.AllocateManagedByteBuffer(this.bytesPerScanline, AllocationOptions.Clean); this.scanline = this.configuration.MemoryAllocator.AllocateManagedByteBuffer(this.bytesPerScanline, AllocationOptions.Clean); } @@ -612,7 +616,7 @@ namespace SixLabors.ImageSharp.Formats.Png throw new ImageFormatException("Unknown filter type."); } - this.ProcessDefilteredScanline(this.scanline.Array, image); + this.ProcessDefilteredScanline(scanlineSpan, image); this.SwapBuffers(); this.currentRow++; @@ -725,7 +729,7 @@ namespace SixLabors.ImageSharp.Formats.Png ReadOnlySpan trimmed = defilteredScanline.Slice(1, defilteredScanline.Length - 1); // Convert 1, 2, and 4 bit pixel data into the 8 bit equivalent. - ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(trimmed, this.bytesPerScanline, this.header.BitDepth, out IManagedByteBuffer buffer) + ReadOnlySpan scanlineSpan = this.TryScaleUpTo8BitArray(trimmed, this.bytesPerScanline - 1, this.header.BitDepth, out IManagedByteBuffer buffer) ? buffer.GetSpan() : trimmed; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index e4d2fc510d..5948f350e0 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -21,6 +21,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// internal sealed class PngEncoderCore : IDisposable { + /// + /// Used the manage memory allocations. + /// private readonly MemoryAllocator memoryAllocator; /// @@ -158,7 +161,9 @@ namespace SixLabors.ImageSharp.Formats.Png this.memoryAllocator = memoryAllocator; this.pngBitDepth = options.BitDepth; this.pngColorType = options.ColorType; - this.pngFilterMethod = options.FilterMethod; + + // Palette compresses better with none and spec recommends it. + this.pngFilterMethod = options.ColorType.Equals(PngColorType.Palette) ? PngFilterMethod.None : options.FilterMethod; this.compressionLevel = options.CompressionLevel; this.gamma = options.Gamma; this.quantizer = options.Quantizer; @@ -192,10 +197,9 @@ namespace SixLabors.ImageSharp.Formats.Png stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); QuantizedFrame quantized = null; - ReadOnlySpan quantizedPixelsSpan = default; if (this.pngColorType == PngColorType.Palette) { - byte bits; + byte bits = (byte)Math.Min(8u, (short)this.pngBitDepth); // Use the metadata to determine what quantization depth to use if no quantizer has been set. if (this.quantizer == null) @@ -207,10 +211,10 @@ namespace SixLabors.ImageSharp.Formats.Png // Create quantized frame returning the palette and set the bit depth. quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); - quantizedPixelsSpan = quantized.GetPixelSpan(); - bits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); + byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk + bits = Math.Max(bits, quantizedBits); if (bits == 3) { bits = 4; @@ -249,7 +253,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.WritePhysicalChunk(stream, metaData); this.WriteGammaChunk(stream); this.WriteExifChunk(stream, metaData); - this.WriteDataChunks(image.Frames.RootFrame, quantizedPixelsSpan, stream); + this.WriteDataChunks(image.Frames.RootFrame, quantized, stream); this.WriteEndChunk(stream); stream.Flush(); @@ -402,10 +406,10 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The pixel format. /// The row span. - /// The span of quantized pixels. Can be null. + /// The quantized pixels. Can be null. /// The row. /// The - private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, ReadOnlySpan quantizedPixelsSpan, int row) + private IManagedByteBuffer EncodePixelRow(ReadOnlySpan rowSpan, QuantizedFrame quantized, int row) where TPixel : struct, IPixel { switch (this.pngColorType) @@ -413,7 +417,14 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Palette: int stride = this.rawScanline.Length(); - quantizedPixelsSpan.Slice(row * stride, stride).CopyTo(this.rawScanline.GetSpan()); + if (this.bitDepth < 8) + { + this.ScaleDownFrom8BitArray(quantized.GetRowSpan(row), this.rawScanline.GetSpan(), this.bitDepth); + } + else + { + quantized.GetPixelSpan().Slice(row * stride, stride).CopyTo(this.rawScanline.GetSpan()); + } break; case PngColorType.Grayscale: @@ -696,9 +707,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The pixel format. /// The image. - /// The span of quantized pixel data. Can be null. + /// The quantized pixel data. Can be null. /// The stream. - private void WriteDataChunks(ImageFrame pixels, ReadOnlySpan quantizedPixelsSpan, Stream stream) + private void WriteDataChunks(ImageFrame pixels, QuantizedFrame quantized, Stream stream) where TPixel : struct, IPixel { this.bytesPerScanline = this.CalculateScanlineLength(this.width); @@ -750,7 +761,7 @@ namespace SixLabors.ImageSharp.Formats.Png { for (int y = 0; y < this.height; y++) { - IManagedByteBuffer r = this.EncodePixelRow((ReadOnlySpan)pixels.GetPixelRowSpan(y), quantizedPixelsSpan, y); + IManagedByteBuffer r = this.EncodePixelRow((ReadOnlySpan)pixels.GetPixelRowSpan(y), quantized, y); deflateStream.Write(r.Array, 0, resultLength); IManagedByteBuffer temp = this.rawScanline; @@ -830,6 +841,42 @@ namespace SixLabors.ImageSharp.Formats.Png stream.Write(this.buffer, 0, 4); // write the crc } + private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits) + { + if (bits >= 8) + { + return; + } + + byte mask = (byte)(0xFF >> (8 - bits)); + byte shift0 = (byte)(8 - bits); + int shift = 8 - bits; + int v = 0; + + for (int i = 0, j = 0; j < source.Length; j++) + { + int value = source[j] & mask; + v |= value << shift; + + if (shift == 0) + { + shift = shift0; + result[i] = (byte)v; + i++; + v = 0; + } + else + { + shift -= bits; + } + } + + if (shift != shift0) + { + result[0] = (byte)v; + } + } + /// /// Calculates the scanline length. /// diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs index 2e3bb2c419..61ea342a8b 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs @@ -59,6 +59,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// The public Span GetPixelSpan() => this.pixels.GetSpan(); + /// + /// Gets the representation of the pixels as a of contiguous memory + /// at row beginning from the the first pixel on that row. + /// + /// The row. + /// The + public Span GetRowSpan(int rowIndex) => this.GetPixelSpan().Slice(rowIndex * this.Width, this.Width); + /// public void Dispose() { From d60048ead223504715c0a17f8120a7f477f26d3c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Sep 2018 12:12:38 +0100 Subject: [PATCH 098/185] Fix 8 bit downscaling --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 5948f350e0..bc7f1906fe 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -852,17 +852,18 @@ namespace SixLabors.ImageSharp.Formats.Png byte shift0 = (byte)(8 - bits); int shift = 8 - bits; int v = 0; + int resultOffset = 0; - for (int i = 0, j = 0; j < source.Length; j++) + for (int i = 0; i < source.Length; i++) { - int value = source[j] & mask; + int value = source[i] & mask; v |= value << shift; if (shift == 0) { shift = shift0; - result[i] = (byte)v; - i++; + result[resultOffset] = (byte)v; + resultOffset++; v = 0; } else @@ -873,7 +874,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (shift != shift0) { - result[0] = (byte)v; + result[resultOffset] = (byte)v; } } From fac94618867f590b3f90b275dd901a94ed717de7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Sep 2018 21:17:08 +0100 Subject: [PATCH 099/185] Optimize x-bit scanline packing. --- .../Formats/Png/IPngEncoderOptions.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 8 ++--- src/ImageSharp/Formats/Png/PngEncoder.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 33 ++++++++++++------- .../Quantization/QuantizedFrame{TPixel}.cs | 4 ++- 5 files changed, 31 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs index 77bc9f7a05..7e5a9fa6b8 100644 --- a/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs +++ b/src/ImageSharp/Formats/Png/IPngEncoderOptions.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets the filter method. /// - PngFilterMethod FilterMethod { get; } + PngFilterMethod? FilterMethod { get; } /// /// Gets the compression level 1-9. diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index c52f974944..0acf0f4bf9 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -396,18 +396,18 @@ namespace SixLabors.ImageSharp.Formats.Png } buffer = this.memoryAllocator.AllocateManagedByteBuffer(bytesPerScanline * 8 / bits, AllocationOptions.Clean); - byte[] result = buffer.Array; + ref byte sourceRef = ref MemoryMarshal.GetReference(source); + ref byte resultRef = ref buffer.Array[0]; int mask = 0xFF >> (8 - bits); int resultOffset = 0; for (int i = 0; i < bytesPerScanline; i++) { - byte b = source[i]; + byte b = Unsafe.Add(ref sourceRef, i); for (int shift = 0; shift < 8; shift += bits) { int colorIndex = (b >> (8 - bits - shift)) & mask; - result[resultOffset] = (byte)colorIndex; - + Unsafe.Add(ref resultRef, resultOffset) = (byte)colorIndex; resultOffset++; } } diff --git a/src/ImageSharp/Formats/Png/PngEncoder.cs b/src/ImageSharp/Formats/Png/PngEncoder.cs index f47a6518f0..96e97a305f 100644 --- a/src/ImageSharp/Formats/Png/PngEncoder.cs +++ b/src/ImageSharp/Formats/Png/PngEncoder.cs @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Gets or sets the filter method. /// - public PngFilterMethod FilterMethod { get; set; } = PngFilterMethod.Paeth; + public PngFilterMethod? FilterMethod { get; set; } /// /// Gets or sets the compression level 1-9. diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index bc7f1906fe..48d611f58b 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -4,6 +4,8 @@ using System; using System.Buffers.Binary; using System.IO; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Png.Filters; @@ -162,8 +164,10 @@ namespace SixLabors.ImageSharp.Formats.Png this.pngBitDepth = options.BitDepth; this.pngColorType = options.ColorType; - // Palette compresses better with none and spec recommends it. - this.pngFilterMethod = options.ColorType.Equals(PngColorType.Palette) ? PngFilterMethod.None : options.FilterMethod; + // Specification recommends default filter method None for paletted images and Paeth for others. + this.pngFilterMethod = options.FilterMethod ?? (options.ColorType.Equals(PngColorType.Palette) + ? PngFilterMethod.None + : PngFilterMethod.Paeth); this.compressionLevel = options.CompressionLevel; this.gamma = options.Gamma; this.quantizer = options.Quantizer; @@ -212,9 +216,11 @@ namespace SixLabors.ImageSharp.Formats.Png // Create quantized frame returning the palette and set the bit depth. quantized = this.quantizer.CreateFrameQuantizer().QuantizeFrame(image.Frames.RootFrame); byte quantizedBits = (byte)ImageMaths.GetBitsNeededForColorDepth(quantized.Palette.Length).Clamp(1, 8); + bits = Math.Max(bits, quantizedBits); // Png only supports in four pixel depths: 1, 2, 4, and 8 bits when using the PLTE chunk - bits = Math.Max(bits, quantizedBits); + // We check again for the bit depth as the bit depth of the color palette from a given quantizer might not + // be within the acceptable range. if (bits == 3) { bits = 4; @@ -228,6 +234,7 @@ namespace SixLabors.ImageSharp.Formats.Png } else { + // TODO: Get the correct bit depth for grayscale images. this.bitDepth = (byte)(this.use16Bit ? 16 : 8); } @@ -416,13 +423,13 @@ namespace SixLabors.ImageSharp.Formats.Png { case PngColorType.Palette: - int stride = this.rawScanline.Length(); if (this.bitDepth < 8) { this.ScaleDownFrom8BitArray(quantized.GetRowSpan(row), this.rawScanline.GetSpan(), this.bitDepth); } else { + int stride = this.rawScanline.Length(); quantized.GetPixelSpan().Slice(row * stride, stride).CopyTo(this.rawScanline.GetSpan()); } @@ -841,12 +848,16 @@ namespace SixLabors.ImageSharp.Formats.Png stream.Write(this.buffer, 0, 4); // write the crc } + /// + /// Packs the given 8 bit array into and array of depths. + /// + /// The source span in 8 bits. + /// The resultant span in . + /// The bit depth. private void ScaleDownFrom8BitArray(ReadOnlySpan source, Span result, int bits) { - if (bits >= 8) - { - return; - } + ref byte sourceRef = ref MemoryMarshal.GetReference(source); + ref byte resultRef = ref MemoryMarshal.GetReference(result); byte mask = (byte)(0xFF >> (8 - bits)); byte shift0 = (byte)(8 - bits); @@ -856,13 +867,13 @@ namespace SixLabors.ImageSharp.Formats.Png for (int i = 0; i < source.Length; i++) { - int value = source[i] & mask; + int value = Unsafe.Add(ref sourceRef, i) & mask; v |= value << shift; if (shift == 0) { shift = shift0; - result[resultOffset] = (byte)v; + Unsafe.Add(ref resultRef, resultOffset) = (byte)v; resultOffset++; v = 0; } @@ -874,7 +885,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (shift != shift0) { - result[resultOffset] = (byte)v; + Unsafe.Add(ref resultRef, resultOffset) = (byte)v; } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs index 61ea342a8b..38862ef446 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizedFrame{TPixel}.cs @@ -3,7 +3,7 @@ using System; using System.Buffers; - +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Memory; @@ -57,6 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// Gets the pixels of this . /// /// The + [MethodImpl(InliningOptions.ShortMethod)] public Span GetPixelSpan() => this.pixels.GetSpan(); /// @@ -65,6 +66,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Quantization /// /// The row. /// The + [MethodImpl(InliningOptions.ShortMethod)] public Span GetRowSpan(int rowIndex) => this.GetPixelSpan().Slice(rowIndex * this.Width, this.Width); /// From c5e5f4734c760b69c5c210cea17e3630c4eba6a7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 26 Sep 2018 23:22:47 +0100 Subject: [PATCH 100/185] Add 1,2, and 4 bit grayscale --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 71 ++++++++++++++++---- 1 file changed, 57 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 48d611f58b..a3ffeb296d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -3,7 +3,9 @@ using System; using System.Buffers.Binary; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; @@ -23,6 +25,18 @@ namespace SixLabors.ImageSharp.Formats.Png /// internal sealed class PngEncoderCore : IDisposable { + /// + /// The dictionary of available color types. + /// + private static readonly Dictionary ColorTypes = new Dictionary() + { + [PngColorType.Grayscale] = new byte[] { 1, 2, 4, 8, 16 }, + [PngColorType.Rgb] = new byte[] { 8, 16 }, + [PngColorType.Palette] = new byte[] { 1, 2, 4, 8 }, + [PngColorType.GrayscaleWithAlpha] = new byte[] { 8, 16 }, + [PngColorType.RgbWithAlpha] = new byte[] { 8, 16 } + }; + /// /// Used the manage memory allocations. /// @@ -198,19 +212,27 @@ namespace SixLabors.ImageSharp.Formats.Png this.pngBitDepth = this.pngBitDepth ?? pngMetaData.BitDepth; this.use16Bit = this.pngBitDepth.Equals(PngBitDepth.Bit16); + // Ensure we are not allowing impossible combinations. + if (!ColorTypes.ContainsKey(this.pngColorType.Value)) + { + throw new NotSupportedException("Color type is not supported or not valid."); + } + stream.Write(PngConstants.HeaderBytes, 0, PngConstants.HeaderBytes.Length); QuantizedFrame quantized = null; if (this.pngColorType == PngColorType.Palette) { - byte bits = (byte)Math.Min(8u, (short)this.pngBitDepth); + byte bits = (byte)this.pngBitDepth; + if (!ColorTypes[this.pngColorType.Value].Contains(bits)) + { + throw new NotSupportedException("Bit depth is not supported or not valid."); + } // Use the metadata to determine what quantization depth to use if no quantizer has been set. if (this.quantizer == null) { - bits = (byte)Math.Min(8u, (short)this.pngBitDepth); - int colorSize = ImageMaths.GetColorCountForBitDepth(bits); - this.quantizer = new WuQuantizer(colorSize); + this.quantizer = new WuQuantizer(ImageMaths.GetColorCountForBitDepth(bits)); } // Create quantized frame returning the palette and set the bit depth. @@ -234,8 +256,11 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - // TODO: Get the correct bit depth for grayscale images. - this.bitDepth = (byte)(this.use16Bit ? 16 : 8); + this.bitDepth = (byte)this.pngBitDepth; + if (!ColorTypes[this.pngColorType.Value].Contains(this.bitDepth)) + { + throw new NotSupportedException("Bit depth is not supported or not valid."); + } } this.bytesPerPixel = this.CalculateBytesPerPixel(); @@ -295,9 +320,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.pngColorType.Equals(PngColorType.Grayscale)) { - // TODO: Realistically we should support 1, 2, 4, 8, and 16 bit grayscale images. - // we currently do the other types via palette. Maybe RC as I don't understand how the data is packed yet - // for 1, 2, and 4 bit grayscale images. + // TODO: Research and add support for grayscale plus tRNS if (this.use16Bit) { // 16 bit grayscale @@ -311,12 +334,32 @@ namespace SixLabors.ImageSharp.Formats.Png } else { - // 8 bit grayscale - Rgb24 rgb = default; - for (int x = 0; x < rowSpan.Length; x++) + if (this.bitDepth == 8) { - rowSpan[x].ToRgb24(ref rgb); - rawScanlineSpan[x] = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); + // 8 bit grayscale + Rgb24 rgb = default; + for (int x = 0; x < rowSpan.Length; x++) + { + rowSpan[x].ToRgb24(ref rgb); + rawScanlineSpan[x] = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); + } + } + else + { + // 1, 2, and 4 bit grayscale + using (IManagedByteBuffer temp = this.memoryAllocator.AllocateManagedByteBuffer(rowSpan.Length, AllocationOptions.Clean)) + { + int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(this.bitDepth) - 1); + Span tempSpan = temp.GetSpan(); + Rgb24 rgb = default; + for (int x = 0; x < rowSpan.Length; x++) + { + rowSpan[x].ToRgb24(ref rgb); + float luminance = ((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)) / scaleFactor; + tempSpan[x] = (byte)luminance; + this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth); + } + } } } } From 0f412fc88b51ffb30b7d6e7c7398c9be90935785 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 13:00:42 +0100 Subject: [PATCH 101/185] Add tests for all supported png bit depths. --- .../Formats/Png/PngEncoderTests.cs | 160 ++++++++---------- .../ReferenceCodecs/MagickReferenceDecoder.cs | 6 +- .../Tests/MagickReferenceCodecTests.cs | 8 +- 3 files changed, 74 insertions(+), 100 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 0508ac8c26..5d328db361 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -9,7 +9,6 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.MetaData; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; @@ -19,10 +18,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { public class PngEncoderTests { - // This is bull. Failing online for no good reason. - // The images are an exact match. Maybe the submodule isn't updating? - private const float ToleranceThresholdForPaletteEncoder = 1.3F / 100; - public static readonly TheoryData PngBitDepthFiles = new TheoryData { @@ -137,19 +132,32 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } [Theory] - [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.Rgb)] - [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.RgbWithAlpha)] - [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.RgbWithAlpha)] - public void WorksWithBitDepth16(TestImageProvider provider, PngColorType pngColorType) + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Rgb, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.Rgb, PngBitDepth.Bit16)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit1)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit2)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit4)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.Palette, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit1)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit2)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit4)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb24, PngColorType.Grayscale, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgb48, PngColorType.Grayscale, PngBitDepth.Bit16)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba32, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)] + [WithTestPatternImages(24, 24, PixelTypes.Rgba64, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit16)] + public void WorksWithAllBitDepths(TestImageProvider provider, PngColorType pngColorType, PngBitDepth pngBitDepth) where TPixel : struct, IPixel { TestPngEncoderCore( provider, pngColorType, PngFilterMethod.Adaptive, - PngBitDepth.Bit16, + pngBitDepth, appendPngColorType: true, - appendPixelType: true); + appendPixelType: true, + appendPngBitDepth: true); } [Theory] @@ -166,87 +174,6 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png appendPaletteSize: true); } - private static bool HasAlpha(PngColorType pngColorType) => - pngColorType == PngColorType.GrayscaleWithAlpha || pngColorType == PngColorType.RgbWithAlpha; - - private static void TestPngEncoderCore( - TestImageProvider provider, - PngColorType pngColorType, - PngFilterMethod pngFilterMethod, - PngBitDepth bitDepth, - int compressionLevel = 6, - int paletteSize = 255, - bool appendPngColorType = false, - bool appendPngFilterMethod = false, - bool appendPixelType = false, - bool appendCompressionLevel = false, - bool appendPaletteSize = false) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage()) - { - if (!HasAlpha(pngColorType)) - { - image.Mutate(c => c.MakeOpaque()); - } - - var encoder = new PngEncoder - { - ColorType = pngColorType, - FilterMethod = pngFilterMethod, - CompressionLevel = compressionLevel, - BitDepth = bitDepth, - Quantizer = new WuQuantizer(paletteSize) - }; - - string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : string.Empty; - string pngFilterMethodInfo = appendPngFilterMethod ? pngFilterMethod.ToString() : string.Empty; - string compressionLevelInfo = appendCompressionLevel ? $"_C{compressionLevel}" : string.Empty; - string paletteSizeInfo = appendPaletteSize ? $"_PaletteSize-{paletteSize}" : string.Empty; - string debugInfo = $"{pngColorTypeInfo}{pngFilterMethodInfo}{compressionLevelInfo}{paletteSizeInfo}"; - //string referenceInfo = $"{pngColorTypeInfo}"; - - // Does DebugSave & load reference CompareToReferenceInput(): - string actualOutputFile = ((ITestImageProvider)provider).Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType); - - if (TestEnvironment.IsMono) - { - // There are bugs in mono's System.Drawing implementation, reference decoders are not always reliable! - return; - } - - IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); - string referenceOutputFile = ((ITestImageProvider)provider).Utility.GetReferenceOutputFileName("png", debugInfo, appendPixelType, true); - - bool referenceOutputFileExists = File.Exists(referenceOutputFile); - - using (var actualImage = Image.Load(actualOutputFile, referenceDecoder)) - { - // TODO: Do we still need the reference output files? - Image referenceImage = referenceOutputFileExists - ? Image.Load(referenceOutputFile, referenceDecoder) - : image; - - float paletteToleranceHack = 80f / paletteSize; - paletteToleranceHack *= paletteToleranceHack; - ImageComparer comparer = pngColorType == PngColorType.Palette - ? ImageComparer.Tolerant(ToleranceThresholdForPaletteEncoder * paletteToleranceHack) - : ImageComparer.Exact; - try - { - comparer.VerifySimilarity(referenceImage, actualImage); - } - finally - { - if (referenceOutputFileExists) - { - referenceImage.Dispose(); - } - } - } - } - } - [Theory] [WithBlankImages(1, 1, PixelTypes.Rgba32)] public void WritesFileMarker(TestImageProvider provider) @@ -321,5 +248,54 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png } } } + + private static void TestPngEncoderCore( + TestImageProvider provider, + PngColorType pngColorType, + PngFilterMethod pngFilterMethod, + PngBitDepth bitDepth, + int compressionLevel = 6, + int paletteSize = 255, + bool appendPngColorType = false, + bool appendPngFilterMethod = false, + bool appendPixelType = false, + bool appendCompressionLevel = false, + bool appendPaletteSize = false, + bool appendPngBitDepth = false) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage()) + { + var encoder = new PngEncoder + { + ColorType = pngColorType, + FilterMethod = pngFilterMethod, + CompressionLevel = compressionLevel, + BitDepth = bitDepth, + Quantizer = new WuQuantizer(paletteSize) + }; + + string pngColorTypeInfo = appendPngColorType ? pngColorType.ToString() : string.Empty; + string pngFilterMethodInfo = appendPngFilterMethod ? pngFilterMethod.ToString() : string.Empty; + string compressionLevelInfo = appendCompressionLevel ? $"_C{compressionLevel}" : string.Empty; + string paletteSizeInfo = appendPaletteSize ? $"_PaletteSize-{paletteSize}" : string.Empty; + string pngBitDepthInfo = appendPngBitDepth ? bitDepth.ToString() : string.Empty; + string debugInfo = $"{pngColorTypeInfo}{pngFilterMethodInfo}{compressionLevelInfo}{paletteSizeInfo}{pngBitDepthInfo}"; + + string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder, debugInfo, appendPixelType); + + // Compare to the Magick reference decoder. + IImageDecoder referenceDecoder = TestEnvironment.GetReferenceDecoder(actualOutputFile); + + // We compare using both our decoder and the reference decoder as pixel transformation + // occurrs within the encoder itself leaving the input image unaffected. + // This means we are benefiting from testing our decoder also. + using (var imageSharpImage = Image.Load(actualOutputFile, new PngDecoder())) + using (var referenceImage = Image.Load(actualOutputFile, referenceDecoder)) + { + ImageComparer.Exact.VerifySimilarity(referenceImage, imageSharpImage); + } + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index 8cfc2472f5..7e942691e9 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -29,13 +29,13 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs { if (magickImage.Depth == 8) { - byte[] data = pixels.ToByteArray("RGBA"); - + byte[] data = pixels.ToByteArray(PixelMapping.RGBA); + PixelOperations.Instance.PackFromRgba32Bytes(data, resultPixels, resultPixels.Length); } else if (magickImage.Depth == 16) { - ushort[] data = pixels.ToShortArray("RGBA"); + ushort[] data = pixels.ToShortArray(PixelMapping.RGBA); Span bytes = MemoryMarshal.Cast(data.AsSpan()); PixelOperations.Instance.PackFromRgba64Bytes(bytes, resultPixels, resultPixels.Length); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs index db651886f2..b60439b488 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/MagickReferenceCodecTests.cs @@ -14,10 +14,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests public class MagickReferenceCodecTests { - public MagickReferenceCodecTests(ITestOutputHelper output) - { - this.Output = output; - } + public MagickReferenceCodecTests(ITestOutputHelper output) => this.Output = output; private ITestOutputHelper Output { get; } @@ -61,6 +58,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests [WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Rgb48Bpp)] [WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Rgb48BppInterlaced)] [WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Rgb48BppTrans)] + [WithBlankImages(1, 1, PixelTypesToTest48, TestImages.Png.Gray16Bit)] public void MagickDecode_16BitDepthImage_IsApproximatelyEquivalentTo_SystemDrawingResult(TestImageProvider dummyProvider, string testImage) where TPixel : struct, IPixel { @@ -71,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities.Tests // 1020 == 4 * 255 (Equivalent to manhattan distance of 1+1+1+1=4 in Rgba32 space) var comparer = ImageComparer.TolerantPercentage(1, 1020); - + using (var mImage = Image.Load(path, magickDecoder)) using (var sdImage = Image.Load(path, sdDecoder)) { From f055564551a61950716551ca3412275891e1e8e6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 15:35:44 +0100 Subject: [PATCH 102/185] Remove index bounds checks from Png decoder --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 190 ++++++++++--------- 1 file changed, 97 insertions(+), 93 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 0acf0f4bf9..8ec3bd9504 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -733,6 +733,9 @@ namespace SixLabors.ImageSharp.Formats.Png ? buffer.GetSpan() : trimmed; + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + switch (this.pngColorType) { case PngColorType.Grayscale: @@ -750,8 +753,9 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.R = luminance; rgb48.G = luminance; rgb48.B = luminance; + pixel.PackFromRgb48(rgb48); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -760,12 +764,13 @@ namespace SixLabors.ImageSharp.Formats.Png var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = 0; x < this.header.Width; x++) { - byte luminance = (byte)(scanlineSpan[x] * factor); + byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * factor); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; + pixel.PackFromRgba32(rgba32); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } } @@ -783,7 +788,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.A = luminance.Equals(this.luminance16Trans) ? ushort.MinValue : ushort.MaxValue; pixel.PackFromRgba64(rgba64); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -791,14 +796,14 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba32 = default; for (int x = 0; x < this.header.Width; x++) { - byte luminance = (byte)(scanlineSpan[x] * factor); + byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * factor); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue; pixel.PackFromRgba32(rgba32); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } } @@ -820,17 +825,18 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.A = alpha; pixel.PackFromRgba64(rgba64); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { Rgba32 rgba32 = default; + int bps = this.bytesPerSample; for (int x = 0; x < this.header.Width; x++) { int offset = x * this.bytesPerPixel; - byte luminance = scanlineSpan[offset]; - byte alpha = scanlineSpan[offset + this.bytesPerSample]; + byte luminance = Unsafe.Add(ref scanlineSpanRef, offset); + byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bps); rgba32.R = luminance; rgba32.G = luminance; @@ -838,7 +844,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba32.A = alpha; pixel.PackFromRgba32(rgba32); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -846,7 +852,39 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Palette: - this.ProcessScanlineFromPalette(scanlineSpan, rowSpan); + ReadOnlySpan palettePixels = MemoryMarshal.Cast(this.palette); + ref Rgb24 palettePixelsRef = ref MemoryMarshal.GetReference(palettePixels); + + if (this.paletteAlpha?.Length > 0) + { + // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha + // channel and we should try to read it. + Rgba32 rgba = default; + ref byte paletteAlphaRef = ref this.paletteAlpha[0]; + + for (int x = 0; x < this.header.Width; x++) + { + int index = Unsafe.Add(ref scanlineSpanRef, x); + rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + rgba.A = this.paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; + + pixel.PackFromRgba32(rgba); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + // TODO: We should have PackFromRgb24. + var rgba = new Rgba32(0, 0, 0, byte.MaxValue); + for (int x = 0; x < this.header.Width; x++) + { + int index = Unsafe.Add(ref scanlineSpanRef, x); + rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + + pixel.PackFromRgba32(rgba); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } break; @@ -862,8 +900,9 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); + pixel.PackFromRgb48(rgb48); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -887,21 +926,22 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.A = rgb48.Equals(this.rgb48Trans) ? ushort.MinValue : ushort.MaxValue; pixel.PackFromRgba64(rgba64); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else { ReadOnlySpan rgb24Span = MemoryMarshal.Cast(scanlineSpan); + ref Rgb24 rgb24SpanRef = ref MemoryMarshal.GetReference(rgb24Span); for (int x = 0; x < this.header.Width; x++) { - ref readonly Rgb24 rgb24 = ref rgb24Span[x]; + ref readonly Rgb24 rgb24 = ref Unsafe.Add(ref rgb24SpanRef, x); Rgba32 rgba32 = default; rgba32.Rgb = rgb24; rgba32.A = rgb24.Equals(this.rgb24Trans) ? byte.MinValue : byte.MaxValue; pixel.PackFromRgba32(rgba32); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } } @@ -919,8 +959,9 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 6, 2)); + pixel.PackFromRgba64(rgba64); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -955,6 +996,9 @@ namespace SixLabors.ImageSharp.Formats.Png ? buffer.GetSpan() : trimmed; + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + switch (this.pngColorType) { case PngColorType.Grayscale: @@ -974,7 +1018,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.B = luminance; pixel.PackFromRgb48(rgb48); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -983,13 +1027,13 @@ namespace SixLabors.ImageSharp.Formats.Png var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { - byte luminance = (byte)(scanlineSpan[o] * factor); + byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * factor); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; pixel.PackFromRgba32(rgba32); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } } @@ -1007,7 +1051,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.A = luminance.Equals(this.luminance16Trans) ? ushort.MinValue : ushort.MaxValue; pixel.PackFromRgba64(rgba64); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -1015,14 +1059,14 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba32 = default; for (int x = pixelOffset; x < this.header.Width; x += increment) { - byte luminance = (byte)(scanlineSpan[x] * factor); + byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * factor); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue; pixel.PackFromRgba32(rgba32); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } } @@ -1044,7 +1088,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.A = alpha; pixel.PackFromRgba64(rgba64); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -1053,15 +1097,15 @@ namespace SixLabors.ImageSharp.Formats.Png for (int x = pixelOffset; x < this.header.Width; x += increment) { int offset = x * this.bytesPerPixel; - byte luminance = scanlineSpan[offset]; - byte alpha = scanlineSpan[offset + this.bytesPerSample]; + byte luminance = Unsafe.Add(ref scanlineSpanRef, offset); + byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + this.bytesPerSample); rgba32.R = luminance; rgba32.G = luminance; rgba32.B = luminance; rgba32.A = alpha; pixel.PackFromRgba32(rgba32); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -1070,20 +1114,22 @@ namespace SixLabors.ImageSharp.Formats.Png case PngColorType.Palette: Span palettePixels = MemoryMarshal.Cast(this.palette); + ref Rgb24 palettePixelsRef = ref MemoryMarshal.GetReference(palettePixels); if (this.paletteAlpha?.Length > 0) { // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha // channel and we should try to read it. Rgba32 rgba = default; + ref byte paletteAlphaRef = ref this.paletteAlpha[0]; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { - int index = scanlineSpan[o]; - rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : byte.MaxValue; - rgba.Rgb = palettePixels[index]; + int index = Unsafe.Add(ref scanlineSpanRef, o); + rgba.A = this.paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; + rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); pixel.PackFromRgba32(rgba); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -1091,11 +1137,11 @@ namespace SixLabors.ImageSharp.Formats.Png var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) { - int index = scanlineSpan[o]; - rgba.Rgb = palettePixels[index]; + int index = Unsafe.Add(ref scanlineSpanRef, o); + rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); pixel.PackFromRgba32(rgba); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -1119,7 +1165,7 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.A = rgb48.Equals(this.rgb48Trans) ? ushort.MinValue : ushort.MaxValue; pixel.PackFromRgba64(rgba64); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -1130,8 +1176,9 @@ namespace SixLabors.ImageSharp.Formats.Png rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); + pixel.PackFromRgb48(rgb48); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } } @@ -1142,13 +1189,13 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) { - rgba.R = scanlineSpan[o]; - rgba.G = scanlineSpan[o + this.bytesPerSample]; - rgba.B = scanlineSpan[o + (2 * this.bytesPerSample)]; + rgba.R = Unsafe.Add(ref scanlineSpanRef, o); + rgba.G = Unsafe.Add(ref scanlineSpanRef, o + this.bytesPerSample); + rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * this.bytesPerSample)); rgba.A = this.rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; pixel.PackFromRgba32(rgba); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -1156,12 +1203,12 @@ namespace SixLabors.ImageSharp.Formats.Png var rgba = new Rgba32(0, 0, 0, byte.MaxValue); for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) { - rgba.R = scanlineSpan[o]; - rgba.G = scanlineSpan[o + this.bytesPerSample]; - rgba.B = scanlineSpan[o + (2 * this.bytesPerSample)]; + rgba.R = Unsafe.Add(ref scanlineSpanRef, o); + rgba.G = Unsafe.Add(ref scanlineSpanRef, o + this.bytesPerSample); + rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * this.bytesPerSample)); pixel.PackFromRgba32(rgba); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } } @@ -1179,8 +1226,9 @@ namespace SixLabors.ImageSharp.Formats.Png rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 6, 2)); + pixel.PackFromRgba64(rgba64); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } else @@ -1188,13 +1236,13 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba = default; for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) { - rgba.R = scanlineSpan[o]; - rgba.G = scanlineSpan[o + this.bytesPerSample]; - rgba.B = scanlineSpan[o + (2 * this.bytesPerSample)]; - rgba.A = scanlineSpan[o + (3 * this.bytesPerSample)]; + rgba.R = Unsafe.Add(ref scanlineSpanRef, o); + rgba.G = Unsafe.Add(ref scanlineSpanRef, o + this.bytesPerSample); + rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * this.bytesPerSample)); + rgba.A = Unsafe.Add(ref scanlineSpanRef, o + (3 * this.bytesPerSample)); pixel.PackFromRgba32(rgba); - rowSpan[x] = pixel; + Unsafe.Add(ref rowSpanRef, x) = pixel; } } @@ -1249,50 +1297,6 @@ namespace SixLabors.ImageSharp.Formats.Png } } - /// - /// Processes a scanline that uses a palette - /// - /// The type of pixel we are expanding to - /// The defiltered scanline - /// The current output image row - private void ProcessScanlineFromPalette(ReadOnlySpan scanline, Span row) - where TPixel : struct, IPixel - { - ReadOnlySpan palettePixels = MemoryMarshal.Cast(this.palette); - var color = default(TPixel); - - if (this.paletteAlpha?.Length > 0) - { - Rgba32 rgba = default; - - // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha - // channel and we should try to read it. - for (int x = 0; x < this.header.Width; x++) - { - int index = scanline[x]; - rgba.A = this.paletteAlpha.Length > index ? this.paletteAlpha[index] : byte.MaxValue; - rgba.Rgb = palettePixels[index]; - - color.PackFromRgba32(rgba); - row[x] = color; - } - } - else - { - // TODO: We should have PackFromRgb24. - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); - for (int x = 0; x < this.header.Width; x++) - { - int index = scanline[x]; - - rgba.Rgb = palettePixels[index]; - - color.PackFromRgba32(rgba); - row[x] = color; - } - } - } - /// /// Reads a header chunk from the data. /// From edcb2ec52fdcbf84480325c0a94422e4278906e8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 16:03:56 +0100 Subject: [PATCH 103/185] Remove index bounds checks from Png encoder --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 41 ++++++++++++-------- 1 file changed, 24 insertions(+), 17 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index a3ffeb296d..603162fbe8 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -316,7 +316,10 @@ namespace SixLabors.ImageSharp.Formats.Png const float RX = .2126F; const float GX = .7152F; const float BX = .0722F; + + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); Span rawScanlineSpan = this.rawScanline.GetSpan(); + ref byte rawScanlineSpanRef = ref MemoryMarshal.GetReference(rawScanlineSpan); if (this.pngColorType.Equals(PngColorType.Grayscale)) { @@ -327,7 +330,7 @@ namespace SixLabors.ImageSharp.Formats.Png Rgb48 rgb = default; for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { - rowSpan[x].ToRgb48(ref rgb); + Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); ushort luminance = (ushort)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); } @@ -340,8 +343,8 @@ namespace SixLabors.ImageSharp.Formats.Png Rgb24 rgb = default; for (int x = 0; x < rowSpan.Length; x++) { - rowSpan[x].ToRgb24(ref rgb); - rawScanlineSpan[x] = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); + Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); + Unsafe.Add(ref rawScanlineSpanRef, x) = (byte)((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)); } } else @@ -351,12 +354,14 @@ namespace SixLabors.ImageSharp.Formats.Png { int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(this.bitDepth) - 1); Span tempSpan = temp.GetSpan(); + ref byte tempSpanRef = ref MemoryMarshal.GetReference(tempSpan); + Rgb24 rgb = default; for (int x = 0; x < rowSpan.Length; x++) { - rowSpan[x].ToRgb24(ref rgb); + Unsafe.Add(ref rowSpanRef, x).ToRgb24(ref rgb); float luminance = ((RX * rgb.R) + (GX * rgb.G) + (BX * rgb.B)) / scaleFactor; - tempSpan[x] = (byte)luminance; + Unsafe.Add(ref tempSpanRef, x) = (byte)luminance; this.ScaleDownFrom8BitArray(tempSpan, rawScanlineSpan, this.bitDepth); } } @@ -371,7 +376,7 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba64 rgba = default; for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 4) { - rowSpan[x].ToRgba64(ref rgba); + Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); ushort luminance = (ushort)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), luminance); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.A); @@ -383,9 +388,9 @@ namespace SixLabors.ImageSharp.Formats.Png Rgba32 rgba = default; for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 2) { - rowSpan[x].ToRgba32(ref rgba); - rawScanlineSpan[o] = (byte)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); - rawScanlineSpan[o + 1] = rgba.A; + Unsafe.Add(ref rowSpanRef, x).ToRgba32(ref rgba); + Unsafe.Add(ref rawScanlineSpanRef, o) = (byte)((RX * rgba.R) + (GX * rgba.G) + (BX * rgba.B)); + Unsafe.Add(ref rawScanlineSpanRef, o + 1) = rgba.A; } } } @@ -421,9 +426,10 @@ namespace SixLabors.ImageSharp.Formats.Png { // 16 bit Rgba Rgba64 rgba = default; + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 8) { - rowSpan[x].ToRgba64(ref rgba); + Unsafe.Add(ref rowSpanRef, x).ToRgba64(ref rgba); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgba.R); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgba.G); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgba.B); @@ -437,9 +443,10 @@ namespace SixLabors.ImageSharp.Formats.Png { // 16 bit Rgb Rgb48 rgb = default; + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); for (int x = 0, o = 0; x < rowSpan.Length; x++, o += 6) { - rowSpan[x].ToRgb48(ref rgb); + Unsafe.Add(ref rowSpanRef, x).ToRgb48(ref rgb); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o, 2), rgb.R); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 2, 2), rgb.G); BinaryPrimitives.WriteUInt16BigEndian(rawScanlineSpan.Slice(o + 4, 2), rgb.B); @@ -630,8 +637,8 @@ namespace SixLabors.ImageSharp.Formats.Png using (IManagedByteBuffer colorTable = this.memoryAllocator.AllocateManagedByteBuffer(colorTableLength)) using (IManagedByteBuffer alphaTable = this.memoryAllocator.AllocateManagedByteBuffer(paletteLength)) { - Span colorTableSpan = colorTable.GetSpan(); - Span alphaTableSpan = alphaTable.GetSpan(); + ref byte colorTableRef = ref MemoryMarshal.GetReference(colorTable.GetSpan()); + ref byte alphaTableRef = ref MemoryMarshal.GetReference(alphaTable.GetSpan()); Span quantizedSpan = quantized.GetPixelSpan(); for (int i = 0; i < paletteLength; i++) @@ -643,9 +650,9 @@ namespace SixLabors.ImageSharp.Formats.Png byte alpha = rgba.A; - colorTableSpan[offset] = rgba.R; - colorTableSpan[offset + 1] = rgba.G; - colorTableSpan[offset + 2] = rgba.B; + Unsafe.Add(ref colorTableRef, offset) = rgba.R; + Unsafe.Add(ref colorTableRef, offset + 1) = rgba.G; + Unsafe.Add(ref colorTableRef, offset + 2) = rgba.B; if (alpha > this.threshold) { @@ -653,7 +660,7 @@ namespace SixLabors.ImageSharp.Formats.Png } anyAlpha = anyAlpha || alpha < byte.MaxValue; - alphaTableSpan[i] = alpha; + Unsafe.Add(ref alphaTableRef, i) = alpha; } } From 5ccf557c9f90ceeb48da4dea84b58defd618a9d7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 17:39:23 +0100 Subject: [PATCH 104/185] Refactor scanline processing so it is readable. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 517 +++------------ .../Formats/Png/PngScanlineProcessor.cs | 600 ++++++++++++++++++ 2 files changed, 678 insertions(+), 439 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/PngScanlineProcessor.cs diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 8ec3bd9504..1bfba68ed6 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -722,7 +722,6 @@ namespace SixLabors.ImageSharp.Formats.Png private void ProcessDefilteredScanline(ReadOnlySpan defilteredScanline, ImageFrame pixels) where TPixel : struct, IPixel { - TPixel pixel = default; Span rowSpan = pixels.GetPixelRowSpan(this.currentRow); // Trim the first marker byte from the buffer @@ -733,241 +732,64 @@ namespace SixLabors.ImageSharp.Formats.Png ? buffer.GetSpan() : trimmed; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); - switch (this.pngColorType) { case PngColorType.Grayscale: - int factor = 255 / (ImageMaths.GetColorCountForBitDepth(this.header.BitDepth) - 1); - - if (!this.hasTrans) - { - if (this.header.BitDepth == 16) - { - Rgb48 rgb48 = default; - for (int x = 0, o = 0; x < this.header.Width; x++, o += 2) - { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.R = luminance; - rgb48.G = luminance; - rgb48.B = luminance; - - pixel.PackFromRgb48(rgb48); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. - var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); - for (int x = 0; x < this.header.Width; x++) - { - byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * factor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - - pixel.PackFromRgba32(rgba32); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - } - else - { - if (this.header.BitDepth == 16) - { - Rgba64 rgba64 = default; - for (int x = 0, o = 0; x < this.header.Width; x++, o += 2) - { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgba64.R = luminance; - rgba64.G = luminance; - rgba64.B = luminance; - rgba64.A = luminance.Equals(this.luminance16Trans) ? ushort.MinValue : ushort.MaxValue; - - pixel.PackFromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - Rgba32 rgba32 = default; - for (int x = 0; x < this.header.Width; x++) - { - byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * factor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue; - - pixel.PackFromRgba32(rgba32); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - } + PngScanlineProcessor.ProcessGrayscaleScanline( + this.header, + scanlineSpan, + rowSpan, + this.hasTrans, + this.luminance16Trans, + this.luminanceTrans); break; case PngColorType.GrayscaleWithAlpha: - if (this.header.BitDepth == 16) - { - Rgba64 rgba64 = default; - for (int x = 0, o = 0; x < this.header.Width; x++, o += 4) - { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - rgba64.R = luminance; - rgba64.G = luminance; - rgba64.B = luminance; - rgba64.A = alpha; - - pixel.PackFromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - Rgba32 rgba32 = default; - int bps = this.bytesPerSample; - for (int x = 0; x < this.header.Width; x++) - { - int offset = x * this.bytesPerPixel; - byte luminance = Unsafe.Add(ref scanlineSpanRef, offset); - byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bps); - - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - rgba32.A = alpha; - - pixel.PackFromRgba32(rgba32); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } + PngScanlineProcessor.ProcessGrayscaleWithAlphaScanline( + this.header, + scanlineSpan, + rowSpan, + this.bytesPerPixel, + this.bytesPerSample); break; case PngColorType.Palette: - ReadOnlySpan palettePixels = MemoryMarshal.Cast(this.palette); - ref Rgb24 palettePixelsRef = ref MemoryMarshal.GetReference(palettePixels); - - if (this.paletteAlpha?.Length > 0) - { - // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha - // channel and we should try to read it. - Rgba32 rgba = default; - ref byte paletteAlphaRef = ref this.paletteAlpha[0]; - - for (int x = 0; x < this.header.Width; x++) - { - int index = Unsafe.Add(ref scanlineSpanRef, x); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); - rgba.A = this.paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; - - pixel.PackFromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - // TODO: We should have PackFromRgb24. - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); - for (int x = 0; x < this.header.Width; x++) - { - int index = Unsafe.Add(ref scanlineSpanRef, x); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); - - pixel.PackFromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } + PngScanlineProcessor.ProcessPaletteScanline( + this.header, + scanlineSpan, + rowSpan, + this.palette, + this.paletteAlpha); break; case PngColorType.Rgb: - if (!this.hasTrans) - { - if (this.header.BitDepth == 16) - { - Rgb48 rgb48 = default; - for (int x = 0, o = 0; x < this.header.Width; x++, o += 6) - { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); - - pixel.PackFromRgb48(rgb48); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - PixelOperations.Instance.PackFromRgb24Bytes(scanlineSpan, rowSpan, this.header.Width); - } - } - else - { - if (this.header.BitDepth == 16) - { - Rgb48 rgb48 = default; - Rgba64 rgba64 = default; - for (int x = 0, o = 0; x < this.header.Width; x++, o += 6) - { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); - - rgba64.Rgb = rgb48; - rgba64.A = rgb48.Equals(this.rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - - pixel.PackFromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - ReadOnlySpan rgb24Span = MemoryMarshal.Cast(scanlineSpan); - ref Rgb24 rgb24SpanRef = ref MemoryMarshal.GetReference(rgb24Span); - for (int x = 0; x < this.header.Width; x++) - { - ref readonly Rgb24 rgb24 = ref Unsafe.Add(ref rgb24SpanRef, x); - Rgba32 rgba32 = default; - rgba32.Rgb = rgb24; - rgba32.A = rgb24.Equals(this.rgb24Trans) ? byte.MinValue : byte.MaxValue; - - pixel.PackFromRgba32(rgba32); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - } + PngScanlineProcessor.ProcessRgbScanline( + this.header, + scanlineSpan, + rowSpan, + this.bytesPerPixel, + this.bytesPerSample, + this.hasTrans, + this.rgb48Trans, + this.rgb24Trans); break; case PngColorType.RgbWithAlpha: - if (this.header.BitDepth == 16) - { - Rgba64 rgba64 = default; - for (int x = 0, o = 0; x < this.header.Width; x++, o += 8) - { - rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); - rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 6, 2)); - - pixel.PackFromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - PixelOperations.Instance.PackFromRgba32Bytes(scanlineSpan, rowSpan, this.header.Width); - } + PngScanlineProcessor.ProcessRgbaScanline( + this.header, + scanlineSpan, + rowSpan, + this.bytesPerPixel, + this.bytesPerSample); break; } @@ -986,8 +808,6 @@ namespace SixLabors.ImageSharp.Formats.Png private void ProcessInterlacedDefilteredScanline(ReadOnlySpan defilteredScanline, Span rowSpan, int pixelOffset = 0, int increment = 1) where TPixel : struct, IPixel { - TPixel pixel = default; - // Trim the first marker byte from the buffer ReadOnlySpan trimmed = defilteredScanline.Slice(1, defilteredScanline.Length - 1); @@ -996,255 +816,74 @@ namespace SixLabors.ImageSharp.Formats.Png ? buffer.GetSpan() : trimmed; - ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); - ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); - switch (this.pngColorType) { case PngColorType.Grayscale: - int factor = 255 / (ImageMaths.GetColorCountForBitDepth(this.header.BitDepth) - 1); - - if (!this.hasTrans) - { - if (this.header.BitDepth == 16) - { - Rgb48 rgb48 = default; - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 2) - { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.R = luminance; - rgb48.G = luminance; - rgb48.B = luminance; - - pixel.PackFromRgb48(rgb48); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. - var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) - { - byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * factor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - - pixel.PackFromRgba32(rgba32); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - } - else - { - if (this.header.BitDepth == 16) - { - Rgba64 rgba64 = default; - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 2) - { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgba64.R = luminance; - rgba64.G = luminance; - rgba64.B = luminance; - rgba64.A = luminance.Equals(this.luminance16Trans) ? ushort.MinValue : ushort.MaxValue; - - pixel.PackFromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - Rgba32 rgba32 = default; - for (int x = pixelOffset; x < this.header.Width; x += increment) - { - byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * factor); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - rgba32.A = luminance.Equals(this.luminanceTrans) ? byte.MinValue : byte.MaxValue; - - pixel.PackFromRgba32(rgba32); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - } + PngScanlineProcessor.ProcessInterlacedGrayscaleScanline( + this.header, + scanlineSpan, + rowSpan, + pixelOffset, + increment, + this.hasTrans, + this.luminance16Trans, + this.luminanceTrans); break; case PngColorType.GrayscaleWithAlpha: - if (this.header.BitDepth == 16) - { - Rgba64 rgba64 = default; - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 4) - { - ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - rgba64.R = luminance; - rgba64.G = luminance; - rgba64.B = luminance; - rgba64.A = alpha; - - pixel.PackFromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - Rgba32 rgba32 = default; - for (int x = pixelOffset; x < this.header.Width; x += increment) - { - int offset = x * this.bytesPerPixel; - byte luminance = Unsafe.Add(ref scanlineSpanRef, offset); - byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + this.bytesPerSample); - rgba32.R = luminance; - rgba32.G = luminance; - rgba32.B = luminance; - rgba32.A = alpha; - - pixel.PackFromRgba32(rgba32); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } + PngScanlineProcessor.ProcessInterlacedGrayscaleWithAlphaScanline( + this.header, + scanlineSpan, + rowSpan, + pixelOffset, + increment, + this.bytesPerPixel, + this.bytesPerSample); break; case PngColorType.Palette: - Span palettePixels = MemoryMarshal.Cast(this.palette); - ref Rgb24 palettePixelsRef = ref MemoryMarshal.GetReference(palettePixels); - - if (this.paletteAlpha?.Length > 0) - { - // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha - // channel and we should try to read it. - Rgba32 rgba = default; - ref byte paletteAlphaRef = ref this.paletteAlpha[0]; - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) - { - int index = Unsafe.Add(ref scanlineSpanRef, o); - rgba.A = this.paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); - - pixel.PackFromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o++) - { - int index = Unsafe.Add(ref scanlineSpanRef, o); - rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); - - pixel.PackFromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } + PngScanlineProcessor.ProcessInterlacedPaletteScanline( + this.header, + scanlineSpan, + rowSpan, + pixelOffset, + increment, + this.palette, + this.paletteAlpha); break; case PngColorType.Rgb: - if (this.header.BitDepth == 16) - { - if (this.hasTrans) - { - Rgb48 rgb48 = default; - Rgba64 rgba64 = default; - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 6) - { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); - - rgba64.Rgb = rgb48; - rgba64.A = rgb48.Equals(this.rgb48Trans) ? ushort.MinValue : ushort.MaxValue; - - pixel.PackFromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - Rgb48 rgb48 = default; - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 6) - { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); - - pixel.PackFromRgb48(rgb48); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - } - else - { - if (this.hasTrans) - { - Rgba32 rgba = default; - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) - { - rgba.R = Unsafe.Add(ref scanlineSpanRef, o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, o + this.bytesPerSample); - rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * this.bytesPerSample)); - rgba.A = this.rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; - - pixel.PackFromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - var rgba = new Rgba32(0, 0, 0, byte.MaxValue); - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) - { - rgba.R = Unsafe.Add(ref scanlineSpanRef, o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, o + this.bytesPerSample); - rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * this.bytesPerSample)); - - pixel.PackFromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - } + PngScanlineProcessor.ProcessInterlacedRgbScanline( + this.header, + scanlineSpan, + rowSpan, + pixelOffset, + increment, + this.bytesPerPixel, + this.bytesPerSample, + this.hasTrans, + this.rgb48Trans, + this.rgb24Trans); break; case PngColorType.RgbWithAlpha: - if (this.header.BitDepth == 16) - { - Rgba64 rgba64 = default; - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += 8) - { - rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 4, 2)); - rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 6, 2)); - - pixel.PackFromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } - else - { - Rgba32 rgba = default; - for (int x = pixelOffset, o = 0; x < this.header.Width; x += increment, o += this.bytesPerPixel) - { - rgba.R = Unsafe.Add(ref scanlineSpanRef, o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, o + this.bytesPerSample); - rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * this.bytesPerSample)); - rgba.A = Unsafe.Add(ref scanlineSpanRef, o + (3 * this.bytesPerSample)); - - pixel.PackFromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; - } - } + PngScanlineProcessor.ProcessInterlacedRgbaScanline( + this.header, + scanlineSpan, + rowSpan, + pixelOffset, + increment, + this.bytesPerPixel, + this.bytesPerSample); break; } diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs new file mode 100644 index 0000000000..6c81ba76c2 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -0,0 +1,600 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Buffers.Binary; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Png +{ + /// + /// Provides methods to allow the decoding of raw scanlines to image rows of different pixel formats. + /// + internal static class PngScanlineProcessor + { + public static void ProcessGrayscaleScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + bool hasTrans, + ushort luminance16Trans, + byte luminanceTrans) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(header.BitDepth) - 1); + + if (!hasTrans) + { + if (header.BitDepth == 16) + { + Rgb48 rgb48 = default; + for (int x = 0, o = 0; x < header.Width; x++, o += 2) + { + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); + rgb48.R = luminance; + rgb48.G = luminance; + rgb48.B = luminance; + + pixel.PackFromRgb48(rgb48); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. + var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); + for (int x = 0; x < header.Width; x++) + { + byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + + pixel.PackFromRgba32(rgba32); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + + return; + } + + if (header.BitDepth == 16) + { + Rgba64 rgba64 = default; + for (int x = 0, o = 0; x < header.Width; x++, o += 2) + { + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); + rgba64.R = luminance; + rgba64.G = luminance; + rgba64.B = luminance; + rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; + + pixel.PackFromRgba64(rgba64); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + Rgba32 rgba32 = default; + for (int x = 0; x < header.Width; x++) + { + byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; + + pixel.PackFromRgba32(rgba32); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + } + + public static void ProcessInterlacedGrayscaleScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + int pixelOffset, + int increment, + bool hasTrans, + ushort luminance16Trans, + byte luminanceTrans) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + int scaleFactor = 255 / (ImageMaths.GetColorCountForBitDepth(header.BitDepth) - 1); + + if (!hasTrans) + { + if (header.BitDepth == 16) + { + Rgb48 rgb48 = default; + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) + { + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); + rgb48.R = luminance; + rgb48.G = luminance; + rgb48.B = luminance; + + pixel.PackFromRgb48(rgb48); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + // TODO: We should really be using Rgb24 here but IPixel does not have a PackFromRgb24 method. + var rgba32 = new Rgba32(0, 0, 0, byte.MaxValue); + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) + { + byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + + pixel.PackFromRgba32(rgba32); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + + return; + } + + if (header.BitDepth == 16) + { + Rgba64 rgba64 = default; + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 2) + { + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); + rgba64.R = luminance; + rgba64.G = luminance; + rgba64.B = luminance; + rgba64.A = luminance.Equals(luminance16Trans) ? ushort.MinValue : ushort.MaxValue; + + pixel.PackFromRgba64(rgba64); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + Rgba32 rgba32 = default; + for (int x = pixelOffset; x < header.Width; x += increment) + { + byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, x) * scaleFactor); + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + rgba32.A = luminance.Equals(luminanceTrans) ? byte.MinValue : byte.MaxValue; + + pixel.PackFromRgba32(rgba32); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + } + + public static void ProcessGrayscaleWithAlphaScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + int bytesPerPixel, + int bytesPerSample) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + + if (header.BitDepth == 16) + { + Rgba64 rgba64 = default; + for (int x = 0, o = 0; x < header.Width; x++, o += 4) + { + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); + ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); + rgba64.R = luminance; + rgba64.G = luminance; + rgba64.B = luminance; + rgba64.A = alpha; + + pixel.PackFromRgba64(rgba64); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + Rgba32 rgba32 = default; + int bps = bytesPerSample; + for (int x = 0; x < header.Width; x++) + { + int offset = x * bytesPerPixel; + byte luminance = Unsafe.Add(ref scanlineSpanRef, offset); + byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bps); + + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + rgba32.A = alpha; + + pixel.PackFromRgba32(rgba32); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + } + + public static void ProcessInterlacedGrayscaleWithAlphaScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + int pixelOffset, + int increment, + int bytesPerPixel, + int bytesPerSample) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + + if (header.BitDepth == 16) + { + Rgba64 rgba64 = default; + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += 4) + { + ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); + ushort alpha = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); + rgba64.R = luminance; + rgba64.G = luminance; + rgba64.B = luminance; + rgba64.A = alpha; + + pixel.PackFromRgba64(rgba64); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + Rgba32 rgba32 = default; + for (int x = pixelOffset; x < header.Width; x += increment) + { + int offset = x * bytesPerPixel; + byte luminance = Unsafe.Add(ref scanlineSpanRef, offset); + byte alpha = Unsafe.Add(ref scanlineSpanRef, offset + bytesPerSample); + rgba32.R = luminance; + rgba32.G = luminance; + rgba32.B = luminance; + rgba32.A = alpha; + + pixel.PackFromRgba32(rgba32); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + } + + public static void ProcessPaletteScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + ReadOnlySpan palette, + byte[] paletteAlpha) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + ReadOnlySpan palettePixels = MemoryMarshal.Cast(palette); + ref Rgb24 palettePixelsRef = ref MemoryMarshal.GetReference(palettePixels); + + if (paletteAlpha?.Length > 0) + { + // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha + // channel and we should try to read it. + Rgba32 rgba = default; + ref byte paletteAlphaRef = ref paletteAlpha[0]; + + for (int x = 0; x < header.Width; x++) + { + int index = Unsafe.Add(ref scanlineSpanRef, x); + rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; + + pixel.PackFromRgba32(rgba); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + // TODO: We should have PackFromRgb24. + var rgba = new Rgba32(0, 0, 0, byte.MaxValue); + for (int x = 0; x < header.Width; x++) + { + int index = Unsafe.Add(ref scanlineSpanRef, x); + rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + + pixel.PackFromRgba32(rgba); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + } + + public static void ProcessInterlacedPaletteScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + int pixelOffset, + int increment, + ReadOnlySpan palette, + byte[] paletteAlpha) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + ReadOnlySpan palettePixels = MemoryMarshal.Cast(palette); + ref Rgb24 palettePixelsRef = ref MemoryMarshal.GetReference(palettePixels); + + if (paletteAlpha?.Length > 0) + { + // If the alpha palette is not null and has one or more entries, this means, that the image contains an alpha + // channel and we should try to read it. + Rgba32 rgba = default; + ref byte paletteAlphaRef = ref paletteAlpha[0]; + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) + { + int index = Unsafe.Add(ref scanlineSpanRef, o); + rgba.A = paletteAlpha.Length > index ? Unsafe.Add(ref paletteAlphaRef, index) : byte.MaxValue; + rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + + pixel.PackFromRgba32(rgba); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + var rgba = new Rgba32(0, 0, 0, byte.MaxValue); + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o++) + { + int index = Unsafe.Add(ref scanlineSpanRef, o); + rgba.Rgb = Unsafe.Add(ref palettePixelsRef, index); + + pixel.PackFromRgba32(rgba); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + } + + public static void ProcessRgbScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + int bytesPerPixel, + int bytesPerSample, + bool hasTrans, + Rgb48 rgb48Trans, + Rgb24 rgb24Trans) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + + if (!hasTrans) + { + if (header.BitDepth == 16) + { + Rgb48 rgb48 = default; + for (int x = 0, o = 0; x < header.Width; x++, o += bytesPerPixel) + { + rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + + pixel.PackFromRgb48(rgb48); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + PixelOperations.Instance.PackFromRgb24Bytes(scanlineSpan, rowSpan, header.Width); + } + + return; + } + + if (header.BitDepth == 16) + { + Rgb48 rgb48 = default; + Rgba64 rgba64 = default; + for (int x = 0, o = 0; x < header.Width; x++, o += bytesPerPixel) + { + rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + + rgba64.Rgb = rgb48; + rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; + + pixel.PackFromRgba64(rgba64); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + ReadOnlySpan rgb24Span = MemoryMarshal.Cast(scanlineSpan); + ref Rgb24 rgb24SpanRef = ref MemoryMarshal.GetReference(rgb24Span); + for (int x = 0; x < header.Width; x++) + { + ref readonly Rgb24 rgb24 = ref Unsafe.Add(ref rgb24SpanRef, x); + Rgba32 rgba32 = default; + rgba32.Rgb = rgb24; + rgba32.A = rgb24.Equals(rgb24Trans) ? byte.MinValue : byte.MaxValue; + + pixel.PackFromRgba32(rgba32); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + } + + public static void ProcessInterlacedRgbScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + int pixelOffset, + int increment, + int bytesPerPixel, + int bytesPerSample, + bool hasTrans, + Rgb48 rgb48Trans, + Rgb24 rgb24Trans) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + + if (header.BitDepth == 16) + { + if (hasTrans) + { + Rgb48 rgb48 = default; + Rgba64 rgba64 = default; + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) + { + rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + + rgba64.Rgb = rgb48; + rgba64.A = rgb48.Equals(rgb48Trans) ? ushort.MinValue : ushort.MaxValue; + + pixel.PackFromRgba64(rgba64); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + Rgb48 rgb48 = default; + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) + { + rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + + pixel.PackFromRgb48(rgb48); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + + return; + } + + if (hasTrans) + { + Rgba32 rgba = default; + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) + { + rgba.R = Unsafe.Add(ref scanlineSpanRef, o); + rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); + rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); + rgba.A = rgb24Trans.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; + + pixel.PackFromRgba32(rgba); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + var rgba = new Rgba32(0, 0, 0, byte.MaxValue); + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) + { + rgba.R = Unsafe.Add(ref scanlineSpanRef, o); + rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); + rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); + + pixel.PackFromRgba32(rgba); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + } + + public static void ProcessRgbaScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + int bytesPerPixel, + int bytesPerSample) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + + if (header.BitDepth == 16) + { + Rgba64 rgba64 = default; + for (int x = 0, o = 0; x < header.Width; x++, o += bytesPerPixel) + { + rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); + + pixel.PackFromRgba64(rgba64); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + PixelOperations.Instance.PackFromRgba32Bytes(scanlineSpan, rowSpan, header.Width); + } + } + + public static void ProcessInterlacedRgbaScanline( + in PngHeader header, + ReadOnlySpan scanlineSpan, + Span rowSpan, + int pixelOffset, + int increment, + int bytesPerPixel, + int bytesPerSample) + where TPixel : struct, IPixel + { + TPixel pixel = default; + ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); + ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); + + if (header.BitDepth == 16) + { + Rgba64 rgba64 = default; + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) + { + rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); + + pixel.PackFromRgba64(rgba64); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + else + { + Rgba32 rgba = default; + for (int x = pixelOffset, o = 0; x < header.Width; x += increment, o += bytesPerPixel) + { + rgba.R = Unsafe.Add(ref scanlineSpanRef, o); + rgba.G = Unsafe.Add(ref scanlineSpanRef, o + bytesPerSample); + rgba.B = Unsafe.Add(ref scanlineSpanRef, o + (2 * bytesPerSample)); + rgba.A = Unsafe.Add(ref scanlineSpanRef, o + (3 * bytesPerSample)); + + pixel.PackFromRgba32(rgba); + Unsafe.Add(ref rowSpanRef, x) = pixel; + } + } + } + } +} \ No newline at end of file From a56f8587cee56478f2260b138c4402e8114b2cde Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 09:17:22 +0100 Subject: [PATCH 105/185] Use clean buffer when detecing format. Fix #714 --- src/ImageSharp/Image.Decode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 894551e08f..8b9f3fdb5b 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -30,7 +30,7 @@ namespace SixLabors.ImageSharp return null; } - using (IManagedByteBuffer buffer = config.MemoryAllocator.AllocateManagedByteBuffer(maxHeaderSize)) + using (IManagedByteBuffer buffer = config.MemoryAllocator.AllocateManagedByteBuffer(maxHeaderSize, AllocationOptions.Clean)) { long startPosition = stream.Position; stream.Read(buffer.Array, 0, maxHeaderSize); From 27b3b00ea1600e2b0e29f0d4684e3d7a6dfa83ba Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 27 Sep 2018 09:17:38 +0100 Subject: [PATCH 106/185] Add tests --- .../Formats/ImageFormatManagerTests.cs | 33 ++++++++++++++----- 1 file changed, 25 insertions(+), 8 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs index 464b1564b8..c2100c302f 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -2,17 +2,15 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Collections.Generic; using System.IO; using System.Linq; +using Moq; using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.IO; -using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Bmp; -using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Gif; -using Moq; +using SixLabors.ImageSharp.Formats.Jpeg; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.PixelFormats; using Xunit; @@ -27,7 +25,7 @@ namespace SixLabors.ImageSharp.Tests { this.DefaultFormatsManager = Configuration.CreateDefaultInstance().ImageFormatsManager; this.FormatsManagerEmpty = new ImageFormatManager(); - } + } [Fact] public void IfAutoloadWellKnownFormatsIsTrueAllFormatsAreLoaded() @@ -114,7 +112,7 @@ namespace SixLabors.ImageSharp.Tests IImageDecoder found2 = this.FormatsManagerEmpty.FindDecoder(TestFormat.GlobalTestFormat); Assert.Equal(decoder2, found2); Assert.NotEqual(found, found2); - } + } [Fact] public void AddFormatCallsConfig() @@ -125,5 +123,24 @@ namespace SixLabors.ImageSharp.Tests provider.Verify(x => x.Configure(config)); } + + [Fact] + public void DetectFormatAllocatesCleanBuffer() + { + byte[] jpegImage; + using (var buffer = new MemoryStream()) + { + using (var image = new Image(100, 100)) + { + image.SaveAsJpeg(buffer); + jpegImage = buffer.ToArray(); + } + } + + byte[] invalidImage = { 1, 2, 3 }; + + Assert.Equal(Image.DetectFormat(jpegImage), JpegFormat.Instance); + Assert.True(Image.DetectFormat(invalidImage) is null); + } } } From 1d6d6578650d0eead1c61920f486b42a710dd000 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:21:45 -0700 Subject: [PATCH 107/185] Move PngHeader parsing logic to struct --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 14 +++----------- src/ImageSharp/Formats/Png/PngHeader.cs | 20 ++++++++++++++++++++ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 1bfba68ed6..d4b29f49d9 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -943,17 +943,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The containing data. private void ReadHeaderChunk(PngMetaData pngMetaData, ReadOnlySpan data) { - byte bitDepth = data[8]; - this.header = new PngHeader( - width: BinaryPrimitives.ReadInt32BigEndian(data.Slice(0, 4)), - height: BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4)), - bitDepth: bitDepth, - colorType: (PngColorType)data[9], - compressionMethod: data[10], - filterMethod: data[11], - interlaceMethod: (PngInterlaceMode)data[12]); - - pngMetaData.BitDepth = (PngBitDepth)bitDepth; + this.header = PngHeader.Parse(data); + + pngMetaData.BitDepth = (PngBitDepth)this.header.BitDepth; pngMetaData.ColorType = this.header.ColorType; } diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs index df85642bed..389ba80aee 100644 --- a/src/ImageSharp/Formats/Png/PngHeader.cs +++ b/src/ImageSharp/Formats/Png/PngHeader.cs @@ -1,6 +1,9 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Buffers.Binary; + namespace SixLabors.ImageSharp.Formats.Png { /// @@ -74,5 +77,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// Two values are currently defined: 0 (no interlace) or 1 (Adam7 interlace). /// public PngInterlaceMode InterlaceMethod { get; } + + /// + /// Parses the PngHeader from the given data buffer. + /// + /// The data to parse. + /// The parsed PngHeader. + public static PngHeader Parse(ReadOnlySpan data) + { + return new PngHeader( + width: BinaryPrimitives.ReadInt32BigEndian(data.Slice(0, 4)), + height: BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4)), + bitDepth: data[8], + colorType: (PngColorType)data[9], + compressionMethod: data[10], + filterMethod: data[11], + interlaceMethod: (PngInterlaceMode)data[12]); + } } } From c3a288091d4205d3e91aebc4f6e0ad8e389f61da Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:22:05 -0700 Subject: [PATCH 108/185] Make ZlibInflateStream getData readonly --- src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs index a92220a595..583175b566 100644 --- a/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs +++ b/src/ImageSharp/Formats/Png/Zlib/ZlibInflateStream.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Zlib /// /// Delegate to get more data once we've exhausted the current data remaining /// - private Func getData; + private readonly Func getData; /// /// Initializes a new instance of the class. From 3a8e6c827b4fe5d901e2093259278e1266510fb7 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:27:18 -0700 Subject: [PATCH 109/185] Move PngHeader writing logic to struct --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 21 +++----------------- src/ImageSharp/Formats/Png/PngHeader.cs | 18 +++++++++++++++++ 2 files changed, 21 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 603162fbe8..525cc8bd1c 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -606,16 +606,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The . private void WriteHeaderChunk(Stream stream, in PngHeader header) { - BinaryPrimitives.WriteInt32BigEndian(this.chunkDataBuffer.AsSpan(0, 4), header.Width); - BinaryPrimitives.WriteInt32BigEndian(this.chunkDataBuffer.AsSpan(4, 4), header.Height); + header.WriteTo(this.chunkDataBuffer); - this.chunkDataBuffer[8] = header.BitDepth; - this.chunkDataBuffer[9] = (byte)header.ColorType; - this.chunkDataBuffer[10] = header.CompressionMethod; - this.chunkDataBuffer[11] = header.FilterMethod; - this.chunkDataBuffer[12] = (byte)header.InterlaceMethod; - - this.WriteChunk(stream, PngChunkType.Header, this.chunkDataBuffer, 0, 13); + this.WriteChunk(stream, PngChunkType.Header, this.chunkDataBuffer, 0, PngHeader.Size); } /// @@ -697,28 +690,24 @@ namespace SixLabors.ImageSharp.Formats.Png switch (meta.ResolutionUnits) { case PixelResolutionUnit.AspectRatio: - this.chunkDataBuffer[8] = 0; BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(meta.HorizontalResolution)); BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(meta.VerticalResolution)); break; case PixelResolutionUnit.PixelsPerInch: - this.chunkDataBuffer[8] = 1; // Per meter BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(UnitConverter.InchToMeter(meta.HorizontalResolution))); BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(UnitConverter.InchToMeter(meta.VerticalResolution))); break; case PixelResolutionUnit.PixelsPerCentimeter: - this.chunkDataBuffer[8] = 1; // Per meter BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(UnitConverter.CmToMeter(meta.HorizontalResolution))); BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(UnitConverter.CmToMeter(meta.VerticalResolution))); break; default: - this.chunkDataBuffer[8] = 1; // Per meter BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(meta.HorizontalResolution)); BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(meta.VerticalResolution)); @@ -782,26 +771,22 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngFilterMethod.Sub: - this.sub = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean); break; case PngFilterMethod.Up: - this.up = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean); break; case PngFilterMethod.Average: - this.average = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean); break; case PngFilterMethod.Paeth: - this.paeth = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean); break; - case PngFilterMethod.Adaptive: + case PngFilterMethod.Adaptive: this.sub = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean); this.up = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean); this.average = this.memoryAllocator.AllocateManagedByteBuffer(resultLength, AllocationOptions.Clean); diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs index 389ba80aee..ec22f1bb42 100644 --- a/src/ImageSharp/Formats/Png/PngHeader.cs +++ b/src/ImageSharp/Formats/Png/PngHeader.cs @@ -11,6 +11,8 @@ namespace SixLabors.ImageSharp.Formats.Png /// internal readonly struct PngHeader { + public const int Size = 13; + public PngHeader( int width, int height, @@ -78,6 +80,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// public PngInterlaceMode InterlaceMethod { get; } + /// + /// Writes the header to the given buffer. + /// + /// The buffer to write to. + public void WriteTo(Span buffer) + { + BinaryPrimitives.WriteInt32BigEndian(buffer.Slice(0, 4), this.Width); + BinaryPrimitives.WriteInt32BigEndian(buffer.Slice(4, 4), this.Height); + + buffer[8] = this.BitDepth; + buffer[9] = (byte)this.ColorType; + buffer[10] = this.CompressionMethod; + buffer[11] = this.FilterMethod; + buffer[12] = (byte)this.InterlaceMethod; + } + /// /// Parses the PngHeader from the given data buffer. /// From 1dd29964721e358d45a0cc84d6530f6883517b3a Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:33:56 -0700 Subject: [PATCH 110/185] Make PngBitDepth a byte --- src/ImageSharp/Formats/Png/PngBitDepth.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngBitDepth.cs b/src/ImageSharp/Formats/Png/PngBitDepth.cs index 396f2c1608..0321b532ab 100644 --- a/src/ImageSharp/Formats/Png/PngBitDepth.cs +++ b/src/ImageSharp/Formats/Png/PngBitDepth.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Provides enumeration for the available PNG bit depths. /// - public enum PngBitDepth + public enum PngBitDepth : byte { /// /// 1 bit per sample or per palette index (not per pixel). From f8cdf4036098b49ff5b94e45b23c99bb405973d9 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:40:25 -0700 Subject: [PATCH 111/185] Use try pattern for reading png chunk length --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 22 +++++++++----------- 1 file changed, 10 insertions(+), 12 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d4b29f49d9..28898bfbd0 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1054,9 +1054,7 @@ namespace SixLabors.ImageSharp.Formats.Png return true; } - int length = this.ReadChunkLength(); - - if (length == -1) + if (!this.TryReadChunkLength(out int length)) { chunk = default; @@ -1070,9 +1068,7 @@ namespace SixLabors.ImageSharp.Formats.Png // That lets us read one byte at a time until we reach a known chunk. this.currentStream.Position -= 3; - length = this.ReadChunkLength(); - - if (length == -1) + if (!this.TryReadChunkLength(out length)) { chunk = default; @@ -1188,16 +1184,18 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// Thrown if the input stream is not valid. /// - private int ReadChunkLength() + private bool TryReadChunkLength(out int result) { - int numBytes = this.currentStream.Read(this.chunkLengthBuffer, 0, 4); - - if (numBytes < 4) + if (this.currentStream.Read(this.chunkLengthBuffer, 0, 4) == 4) { - return -1; + result = BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer); + + return true; } - return BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer); + result = default; + + return false; } /// From 38a13de46623ef8ccb35524e5aa41ba49cbf0bc2 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:51:40 -0700 Subject: [PATCH 112/185] Breakout Adam7 constants and methods --- src/ImageSharp/Formats/Png/Adam7.cs | 56 ++++++++++++++++++++ src/ImageSharp/Formats/Png/PngDecoderCore.cs | 52 ++---------------- 2 files changed, 61 insertions(+), 47 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/Adam7.cs diff --git a/src/ImageSharp/Formats/Png/Adam7.cs b/src/ImageSharp/Formats/Png/Adam7.cs new file mode 100644 index 0000000000..4e6485b55f --- /dev/null +++ b/src/ImageSharp/Formats/Png/Adam7.cs @@ -0,0 +1,56 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.Formats.Png +{ + /// + /// Constants and helper methods for the Adam7 interlacing algorithm. + /// + internal static class Adam7 + { + /// + /// The amount to increment when processing each column per scanline for each interlaced pass. + /// + public static readonly int[] ColumnIncrement = { 8, 8, 4, 4, 2, 2, 1 }; + + /// + /// The index to start at when processing each column per scanline for each interlaced pass. + /// + public static readonly int[] FirstColumn = { 0, 4, 0, 2, 0, 1, 0 }; + + /// + /// The index to start at when processing each row per scanline for each interlaced pass. + /// + public static readonly int[] FirstRow = { 0, 0, 4, 0, 2, 0, 1 }; + + /// + /// The amount to increment when processing each row per scanline for each interlaced pass. + /// + public static readonly int[] RowIncrement = { 8, 8, 8, 4, 4, 2, 2 }; + + /// + /// Returns the correct number of columns for each interlaced pass. + /// + /// The line width. + /// The current pass index. + /// The + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static int ComputeColumns(int width, int passIndex) + { + switch (passIndex) + { + case 0: return (width + 7) / 8; + case 1: return (width + 3) / 8; + case 2: return (width + 3) / 4; + case 3: return (width + 1) / 4; + case 4: return (width + 1) / 2; + case 5: return width / 2; + case 6: return width; + default: throw new ArgumentException($"Not a valid pass index: {passIndex}"); + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 28898bfbd0..a728bb2964 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -37,26 +37,6 @@ namespace SixLabors.ImageSharp.Formats.Png [PngColorType.RgbWithAlpha] = new byte[] { 8, 16 } }; - /// - /// The amount to increment when processing each column per scanline for each interlaced pass - /// - private static readonly int[] Adam7ColumnIncrement = { 8, 8, 4, 4, 2, 2, 1 }; - - /// - /// The index to start at when processing each column per scanline for each interlaced pass - /// - private static readonly int[] Adam7FirstColumn = { 0, 4, 0, 2, 0, 1, 0 }; - - /// - /// The index to start at when processing each row per scanline for each interlaced pass - /// - private static readonly int[] Adam7FirstRow = { 0, 0, 4, 0, 2, 0, 1 }; - - /// - /// The amount to increment when processing each row per scanline for each interlaced pass - /// - private static readonly int[] Adam7RowIncrement = { 8, 8, 8, 4, 4, 2, 2 }; - /// /// Reusable buffer for reading chunk types. /// @@ -150,7 +130,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The index of the current scanline being processed /// - private int currentRow = Adam7FirstRow[0]; + private int currentRow = Adam7.FirstRow[0]; /// /// The current pass for an interlaced PNG @@ -635,7 +615,7 @@ namespace SixLabors.ImageSharp.Formats.Png { while (true) { - int numColumns = this.ComputeColumnsAdam7(this.pass); + int numColumns = Adam7.ComputeColumns(this.header.Width, this.pass); if (numColumns == 0) { @@ -691,11 +671,11 @@ namespace SixLabors.ImageSharp.Formats.Png } Span rowSpan = image.GetPixelRowSpan(this.currentRow); - this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, Adam7FirstColumn[this.pass], Adam7ColumnIncrement[this.pass]); + this.ProcessInterlacedDefilteredScanline(this.scanline.GetSpan(), rowSpan, Adam7.FirstColumn[this.pass], Adam7.ColumnIncrement[this.pass]); this.SwapBuffers(); - this.currentRow += Adam7RowIncrement[this.pass]; + this.currentRow += Adam7.RowIncrement[this.pass]; } this.pass++; @@ -703,7 +683,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.pass < 7) { - this.currentRow = Adam7FirstRow[this.pass]; + this.currentRow = Adam7.FirstRow[this.pass]; } else { @@ -1198,28 +1178,6 @@ namespace SixLabors.ImageSharp.Formats.Png return false; } - /// - /// Returns the correct number of columns for each interlaced pass. - /// - /// Th current pass index - /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private int ComputeColumnsAdam7(int passIndex) - { - int width = this.header.Width; - switch (passIndex) - { - case 0: return (width + 7) / 8; - case 1: return (width + 3) / 8; - case 2: return (width + 3) / 4; - case 3: return (width + 1) / 4; - case 4: return (width + 1) / 2; - case 5: return width / 2; - case 6: return width; - default: throw new ArgumentException($"Not a valid pass index: {passIndex}"); - } - } - private void SwapBuffers() { IManagedByteBuffer temp = this.previousScanline; From 7465afe6f2d9dfac94465343657281ac103e7040 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 15:56:00 -0700 Subject: [PATCH 113/185] Ensure 4 bytes are read when reading png chunk type --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index a728bb2964..3b67146b96 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1148,14 +1148,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// private PngChunkType ReadChunkType() { - int numBytes = this.currentStream.Read(this.chunkTypeBuffer, 0, 4); - - if (numBytes >= 1 && numBytes <= 3) - { - throw new ImageFormatException("Image stream is not valid!"); - } - - return (PngChunkType)BinaryPrimitives.ReadUInt32BigEndian(this.chunkTypeBuffer.AsSpan()); + return this.currentStream.Read(this.chunkTypeBuffer, 0, 4) == 4 + ? (PngChunkType)BinaryPrimitives.ReadUInt32BigEndian(this.chunkTypeBuffer.AsSpan()) + : throw new ImageFormatException("Invalid PNG data."); } /// From 662ce2ca09a88ad1b13da71a57b637a5425d0b0f Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Sat, 29 Sep 2018 16:03:50 -0700 Subject: [PATCH 114/185] Format PNG filters --- .../Formats/Png/Filters/AverageFilter.cs | 14 +++++++------- src/ImageSharp/Formats/Png/Filters/PaethFilter.cs | 6 ++++-- src/ImageSharp/Formats/Png/Filters/SubFilter.cs | 6 ++++-- 3 files changed, 15 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs index ffcf9b0f30..bc5a54e8b9 100644 --- a/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/AverageFilter.cs @@ -30,7 +30,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters // Average(x) + floor((Raw(x-bpp)+Prior(x))/2) int x = 1; - for (; x <= bytesPerPixel /* Note the <= because x starts at 1 */; ++x) { + for (; x <= bytesPerPixel /* Note the <= because x starts at 1 */; ++x) + { ref byte scan = ref Unsafe.Add(ref scanBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x); scan = (byte)(scan + (above >> 1)); @@ -68,7 +69,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters resultBaseRef = 3; int x = 0; - for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) { + for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) + { byte scan = Unsafe.Add(ref scanBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x); ++x; @@ -77,7 +79,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters sum += ImageMaths.FastAbs(unchecked((sbyte)res)); } - for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) { + for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) + { byte scan = Unsafe.Add(ref scanBaseRef, x); byte left = Unsafe.Add(ref scanBaseRef, xLeft); byte above = Unsafe.Add(ref prevBaseRef, x); @@ -97,9 +100,6 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters /// The above byte /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int Average(byte left, byte above) - { - return (left + above) >> 1; - } + private static int Average(byte left, byte above) => (left + above) >> 1; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs index 0d3df079c9..4ffc39bdbd 100644 --- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs @@ -72,7 +72,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters resultBaseRef = 4; int x = 0; - for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) { + for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) + { byte scan = Unsafe.Add(ref scanBaseRef, x); byte above = Unsafe.Add(ref prevBaseRef, x); ++x; @@ -81,7 +82,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters sum += ImageMaths.FastAbs(unchecked((sbyte)res)); } - for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) { + for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) + { byte scan = Unsafe.Add(ref scanBaseRef, x); byte left = Unsafe.Add(ref scanBaseRef, xLeft); byte above = Unsafe.Add(ref prevBaseRef, x); diff --git a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs index cfb7781be4..6af5f0b648 100644 --- a/src/ImageSharp/Formats/Png/Filters/SubFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/SubFilter.cs @@ -59,7 +59,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters resultBaseRef = 1; int x = 0; - for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) { + for (; x < bytesPerPixel; /* Note: ++x happens in the body to avoid one add operation */) + { byte scan = Unsafe.Add(ref scanBaseRef, x); ++x; ref byte res = ref Unsafe.Add(ref resultBaseRef, x); @@ -67,7 +68,8 @@ namespace SixLabors.ImageSharp.Formats.Png.Filters sum += ImageMaths.FastAbs(unchecked((sbyte)res)); } - for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) { + for (int xLeft = x - bytesPerPixel; x < scanline.Length; ++xLeft /* Note: ++x happens in the body to avoid one add operation */) + { byte scan = Unsafe.Add(ref scanBaseRef, x); byte prev = Unsafe.Add(ref scanBaseRef, xLeft); ++x; From f5e677c862fab233e7789742e6893603a268332d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sv=C3=A5n=C3=A5?= Date: Sun, 30 Sep 2018 20:49:24 +0200 Subject: [PATCH 115/185] When passing 0 to only one dimension on resize, it will keep one pixel in case aspect ratio results in less than 1 pixel for a dimension. --- .../Processors/Transforms/ResizeProcessor.cs | 63 +++++++++++++------ .../Processors/Transforms/ResizeTests.cs | 34 ++++++++-- 2 files changed, 74 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 76abc64996..2f1ef68652 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -40,25 +40,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Guard.NotNull(options, nameof(options)); Guard.NotNull(options.Sampler, nameof(options.Sampler)); - int tempWidth = options.Size.Width; - int tempHeight = options.Size.Height; + int targetWidth = options.Size.Width; + int targetHeight = options.Size.Height; // Ensure size is populated across both dimensions. // These dimensions are used to calculate the final dimensions determined by the mode algorithm. - if (tempWidth == 0 && tempHeight > 0) - { - tempWidth = (int)MathF.Round(sourceSize.Width * tempHeight / (float)sourceSize.Height); - } - - if (tempHeight == 0 && tempWidth > 0) - { - tempHeight = (int)MathF.Round(sourceSize.Height * tempWidth / (float)sourceSize.Width); - } - - Guard.MustBeGreaterThan(tempWidth, 0, nameof(tempWidth)); - Guard.MustBeGreaterThan(tempHeight, 0, nameof(tempHeight)); + EnsureSizeBothDimensions(sourceSize.Width, sourceSize.Height, ref targetWidth, ref targetHeight, out _, out _); - (Size size, Rectangle rectangle) = ResizeHelper.CalculateTargetLocationAndBounds(sourceSize, options, tempWidth, tempHeight); + (Size size, Rectangle rectangle) = ResizeHelper.CalculateTargetLocationAndBounds(sourceSize, options, targetWidth, targetHeight); this.Sampler = options.Sampler; this.Width = size.Width; @@ -95,15 +84,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Guard.NotNull(sampler, nameof(sampler)); // Ensure size is populated across both dimensions. - if (width == 0 && height > 0) + EnsureSizeBothDimensions(sourceSize.Width, sourceSize.Height, ref width, ref height, out bool changedWidth, out bool changedHeight); + if (changedWidth) { - width = (int)MathF.Round(sourceSize.Width * height / (float)sourceSize.Height); resizeRectangle.Width = width; } - if (height == 0 && width > 0) + if (changedHeight) { - height = (int)MathF.Round(sourceSize.Height * width / (float)sourceSize.Width); resizeRectangle.Height = height; } @@ -142,6 +130,43 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// public bool Compand { get; } + /// + /// Makes sure both target dimensions are >= 1. + /// If only one of the incoming dimensions is 0, it will be modified here to maintain aspect ratio. + /// If it is not possible to keep aspect ratio, make sure at least 1 pixel is kept. + /// + private static void EnsureSizeBothDimensions( + int sourceWidth, + int sourceHeight, + ref int targetWidth, + ref int targetHeight, + out bool changedTargetWidth, + out bool changedTargetHeight) + { + if (targetWidth == 0 && targetHeight > 0) + { + targetWidth = Math.Max(1, (int)MathF.Round(sourceWidth * targetHeight / (float)sourceHeight)); + changedTargetWidth = true; + } + else + { + changedTargetWidth = false; + } + + if (targetHeight == 0 && targetWidth > 0) + { + targetHeight = Math.Max(1, (int)MathF.Round(sourceHeight * targetWidth / (float)sourceWidth)); + changedTargetHeight = true; + } + else + { + changedTargetHeight = false; + } + + Guard.MustBeGreaterThan(targetWidth, 0, nameof(targetWidth)); + Guard.MustBeGreaterThan(targetHeight, 0, nameof(targetHeight)); + } + /// /// Computes the weights to apply at each pixel when resizing. /// diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 746d8da16e..d1d473bbd2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -178,6 +178,32 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } + [Theory] + [WithTestPatternImages(100, 10, DefaultPixelType)] + public void ResizeWidthCannotKeepAspectKeepsOnePixel(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage()) + { + image.Mutate(x => x.Resize(5, 0)); + Assert.Equal(5, image.Width); + Assert.Equal(1, image.Height); + } + } + + [Theory] + [WithTestPatternImages(10, 100, DefaultPixelType)] + public void ResizeHeightCannotKeepAspectKeepsOnePixel(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage()) + { + image.Mutate(x => x.Resize(0, 5)); + Assert.Equal(1, image.Width); + Assert.Equal(5, image.Height); + } + } + [Theory] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] public void ResizeWithCropWidthMode(TestImageProvider provider) @@ -324,7 +350,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [InlineData(2, 0)] public static void BicubicWindowOscillatesCorrectly(float x, float expected) { - var sampler = KnownResamplers.Bicubic; + IResampler sampler = KnownResamplers.Bicubic; float result = sampler.GetValue(x); Assert.Equal(result, expected); @@ -338,7 +364,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [InlineData(2, 0)] public static void TriangleWindowOscillatesCorrectly(float x, float expected) { - var sampler = KnownResamplers.Triangle; + IResampler sampler = KnownResamplers.Triangle; float result = sampler.GetValue(x); Assert.Equal(result, expected); @@ -352,7 +378,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [InlineData(2, 0)] public static void Lanczos3WindowOscillatesCorrectly(float x, float expected) { - var sampler = KnownResamplers.Lanczos3; + IResampler sampler = KnownResamplers.Lanczos3; float result = sampler.GetValue(x); Assert.Equal(result, expected); @@ -366,7 +392,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms [InlineData(4, 0)] public static void Lanczos5WindowOscillatesCorrectly(float x, float expected) { - var sampler = KnownResamplers.Lanczos5; + IResampler sampler = KnownResamplers.Lanczos5; float result = sampler.GetValue(x); Assert.Equal(result, expected); From 49fb759f2918a385f99b9af89743166cd7ff0a6d Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 15:55:35 -0700 Subject: [PATCH 116/185] Unify PngDecoder buffer --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 51 ++++++++------------ 1 file changed, 20 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 3b67146b96..3ac13eb58a 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -38,19 +38,9 @@ namespace SixLabors.ImageSharp.Formats.Png }; /// - /// Reusable buffer for reading chunk types. + /// Reusable buffer. /// - private readonly byte[] chunkTypeBuffer = new byte[4]; - - /// - /// Reusable buffer for reading chunk lengths. - /// - private readonly byte[] chunkLengthBuffer = new byte[4]; - - /// - /// Reusable buffer for reading crc values. - /// - private readonly byte[] crcBuffer = new byte[4]; + private readonly byte[] buffer = new byte[4]; /// /// Reusable crc for validating chunks. @@ -1001,7 +991,7 @@ namespace SixLabors.ImageSharp.Formats.Png return 0; } - this.currentStream.Read(this.crcBuffer, 0, 4); + this.currentStream.Read(this.buffer, 0, 4); if (this.TryReadChunk(out PngChunk chunk)) { @@ -1086,13 +1076,17 @@ namespace SixLabors.ImageSharp.Formats.Png /// The . private void ValidateChunk(in PngChunk chunk) { + Span chunkType = stackalloc byte[4]; + + BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); + this.crc.Reset(); - this.crc.Update(this.chunkTypeBuffer); + this.crc.Update(chunkType); this.crc.Update(chunk.Data.GetSpan()); if (this.crc.Value != chunk.Crc) { - string chunkTypeName = Encoding.UTF8.GetString(this.chunkTypeBuffer, 0, 4); + string chunkTypeName = Encoding.UTF8.GetString(chunkType.ToArray(), 0, 4); throw new ImageFormatException($"CRC Error. PNG {chunkTypeName} chunk is corrupt!"); } @@ -1106,14 +1100,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// private uint ReadChunkCrc() { - int numBytes = this.currentStream.Read(this.crcBuffer, 0, 4); - - if (numBytes >= 1 && numBytes <= 3) - { - throw new ImageFormatException("Image stream is not valid!"); - } - - return BinaryPrimitives.ReadUInt32BigEndian(this.crcBuffer); + return this.currentStream.Read(this.buffer, 0, 4) == 4 + ? BinaryPrimitives.ReadUInt32BigEndian(this.buffer) + : throw new ImageFormatException("Image stream is not valid!"); } /// @@ -1148,22 +1137,22 @@ namespace SixLabors.ImageSharp.Formats.Png /// private PngChunkType ReadChunkType() { - return this.currentStream.Read(this.chunkTypeBuffer, 0, 4) == 4 - ? (PngChunkType)BinaryPrimitives.ReadUInt32BigEndian(this.chunkTypeBuffer.AsSpan()) + return this.currentStream.Read(this.buffer, 0, 4) == 4 + ? (PngChunkType)BinaryPrimitives.ReadUInt32BigEndian(this.buffer) : throw new ImageFormatException("Invalid PNG data."); } /// - /// Calculates the length of the given chunk. + /// Attempts to read the length of the next chunk. /// - /// - /// Thrown if the input stream is not valid. - /// + /// + /// Whether the the length was read. + /// private bool TryReadChunkLength(out int result) { - if (this.currentStream.Read(this.chunkLengthBuffer, 0, 4) == 4) + if (this.currentStream.Read(this.buffer, 0, 4) == 4) { - result = BinaryPrimitives.ReadInt32BigEndian(this.chunkLengthBuffer); + result = BinaryPrimitives.ReadInt32BigEndian(this.buffer); return true; } From 7c88e011be4303296c61254d079074e510e5f916 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 15:57:26 -0700 Subject: [PATCH 117/185] Remove extra line breaks --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 3ac13eb58a..fa509336e7 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -563,22 +563,18 @@ namespace SixLabors.ImageSharp.Formats.Png break; case FilterType.Sub: - SubFilter.Decode(scanlineSpan, this.bytesPerPixel); break; case FilterType.Up: - UpFilter.Decode(scanlineSpan, this.previousScanline.GetSpan()); break; case FilterType.Average: - AverageFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel); break; case FilterType.Paeth: - PaethFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel); break; @@ -637,22 +633,18 @@ namespace SixLabors.ImageSharp.Formats.Png break; case FilterType.Sub: - SubFilter.Decode(scanSpan, this.bytesPerPixel); break; case FilterType.Up: - UpFilter.Decode(scanSpan, prevSpan); break; case FilterType.Average: - AverageFilter.Decode(scanSpan, prevSpan, this.bytesPerPixel); break; case FilterType.Paeth: - PaethFilter.Decode(scanSpan, prevSpan, this.bytesPerPixel); break; @@ -705,7 +697,6 @@ namespace SixLabors.ImageSharp.Formats.Png switch (this.pngColorType) { case PngColorType.Grayscale: - PngScanlineProcessor.ProcessGrayscaleScanline( this.header, scanlineSpan, @@ -717,7 +708,6 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngColorType.GrayscaleWithAlpha: - PngScanlineProcessor.ProcessGrayscaleWithAlphaScanline( this.header, scanlineSpan, @@ -728,7 +718,6 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngColorType.Palette: - PngScanlineProcessor.ProcessPaletteScanline( this.header, scanlineSpan, @@ -739,7 +728,6 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngColorType.Rgb: - PngScanlineProcessor.ProcessRgbScanline( this.header, scanlineSpan, @@ -753,7 +741,6 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngColorType.RgbWithAlpha: - PngScanlineProcessor.ProcessRgbaScanline( this.header, scanlineSpan, @@ -789,7 +776,6 @@ namespace SixLabors.ImageSharp.Formats.Png switch (this.pngColorType) { case PngColorType.Grayscale: - PngScanlineProcessor.ProcessInterlacedGrayscaleScanline( this.header, scanlineSpan, @@ -803,7 +789,6 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngColorType.GrayscaleWithAlpha: - PngScanlineProcessor.ProcessInterlacedGrayscaleWithAlphaScanline( this.header, scanlineSpan, @@ -816,7 +801,6 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngColorType.Palette: - PngScanlineProcessor.ProcessInterlacedPaletteScanline( this.header, scanlineSpan, @@ -829,7 +813,6 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngColorType.Rgb: - PngScanlineProcessor.ProcessInterlacedRgbScanline( this.header, scanlineSpan, @@ -845,7 +828,6 @@ namespace SixLabors.ImageSharp.Formats.Png break; case PngColorType.RgbWithAlpha: - PngScanlineProcessor.ProcessInterlacedRgbaScanline( this.header, scanlineSpan, From c29a967e26bce334d62521fd4cb6daa56567efb9 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:19:24 -0700 Subject: [PATCH 118/185] Move Png ColorType to Constants --- src/ImageSharp/Formats/Png/PngConstants.cs | 12 ++++++++++++ src/ImageSharp/Formats/Png/PngDecoderCore.cs | 17 +++-------------- 2 files changed, 15 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngConstants.cs b/src/ImageSharp/Formats/Png/PngConstants.cs index ff25e26b7a..48c866f671 100644 --- a/src/ImageSharp/Formats/Png/PngConstants.cs +++ b/src/ImageSharp/Formats/Png/PngConstants.cs @@ -41,5 +41,17 @@ namespace SixLabors.ImageSharp.Formats.Png /// The header bytes as a big endian coded ulong. /// public const ulong HeaderValue = 0x89504E470D0A1A0AUL; + + /// + /// The dictionary of available color types. + /// + public static readonly Dictionary ColorTypes = new Dictionary() + { + [PngColorType.Grayscale] = new byte[] { 1, 2, 4, 8, 16 }, + [PngColorType.Rgb] = new byte[] { 8, 16 }, + [PngColorType.Palette] = new byte[] { 1, 2, 4, 8 }, + [PngColorType.GrayscaleWithAlpha] = new byte[] { 8, 16 }, + [PngColorType.RgbWithAlpha] = new byte[] { 8, 16 } + }; } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index fa509336e7..a24b69160a 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -25,18 +25,6 @@ namespace SixLabors.ImageSharp.Formats.Png /// internal sealed class PngDecoderCore { - /// - /// The dictionary of available color types. - /// - private static readonly Dictionary ColorTypes = new Dictionary() - { - [PngColorType.Grayscale] = new byte[] { 1, 2, 4, 8, 16 }, - [PngColorType.Rgb] = new byte[] { 8, 16 }, - [PngColorType.Palette] = new byte[] { 1, 2, 4, 8 }, - [PngColorType.GrayscaleWithAlpha] = new byte[] { 8, 16 }, - [PngColorType.RgbWithAlpha] = new byte[] { 8, 16 } - }; - /// /// Reusable buffer. /// @@ -858,6 +846,7 @@ namespace SixLabors.ImageSharp.Formats.Png ushort rc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(0, 2)); ushort gc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(2, 2)); ushort bc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(4, 2)); + this.rgb48Trans = new Rgb48(rc, gc, bc); this.hasTrans = true; return; @@ -909,12 +898,12 @@ namespace SixLabors.ImageSharp.Formats.Png /// private void ValidateHeader() { - if (!ColorTypes.ContainsKey(this.header.ColorType)) + if (!PngConstants.ColorTypes.ContainsKey(this.header.ColorType)) { throw new NotSupportedException("Color type is not supported or not valid."); } - if (!ColorTypes[this.header.ColorType].Contains(this.header.BitDepth)) + if (!PngConstants.ColorTypes[this.header.ColorType].Contains(this.header.BitDepth)) { throw new NotSupportedException("Bit depth is not supported or not valid."); } From 666aaffaab7e6fb850d73cfc75f40dc7e281b1d4 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:23:38 -0700 Subject: [PATCH 119/185] Move PngHeader validation to struct --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 33 ++------------------ src/ImageSharp/Formats/Png/PngHeader.cs | 29 +++++++++++++++++ 2 files changed, 31 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index a24b69160a..112dc72623 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -198,7 +198,6 @@ namespace SixLabors.ImageSharp.Formats.Png { case PngChunkType.Header: this.ReadHeaderChunk(pngMetaData, chunk.Data.Array); - this.ValidateHeader(); break; case PngChunkType.Physical: this.ReadPhysicalChunk(metaData, chunk.Data.GetSpan()); @@ -287,7 +286,6 @@ namespace SixLabors.ImageSharp.Formats.Png { case PngChunkType.Header: this.ReadHeaderChunk(pngMetaData, chunk.Data.Array); - this.ValidateHeader(); break; case PngChunkType.Physical: this.ReadPhysicalChunk(metaData, chunk.Data.GetSpan()); @@ -886,37 +884,10 @@ namespace SixLabors.ImageSharp.Formats.Png { this.header = PngHeader.Parse(data); + this.header.Validate(); + pngMetaData.BitDepth = (PngBitDepth)this.header.BitDepth; pngMetaData.ColorType = this.header.ColorType; - } - - /// - /// Validates the png header. - /// - /// - /// Thrown if the image does pass validation. - /// - private void ValidateHeader() - { - if (!PngConstants.ColorTypes.ContainsKey(this.header.ColorType)) - { - throw new NotSupportedException("Color type is not supported or not valid."); - } - - if (!PngConstants.ColorTypes[this.header.ColorType].Contains(this.header.BitDepth)) - { - throw new NotSupportedException("Bit depth is not supported or not valid."); - } - - if (this.header.FilterMethod != 0) - { - throw new NotSupportedException("The png specification only defines 0 as filter method."); - } - - if (this.header.InterlaceMethod != PngInterlaceMode.None && this.header.InterlaceMethod != PngInterlaceMode.Adam7) - { - throw new NotSupportedException("The png specification only defines 'None' and 'Adam7' as interlaced methods."); - } this.pngColorType = this.header.ColorType; } diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs index ec22f1bb42..0523502b05 100644 --- a/src/ImageSharp/Formats/Png/PngHeader.cs +++ b/src/ImageSharp/Formats/Png/PngHeader.cs @@ -80,6 +80,35 @@ namespace SixLabors.ImageSharp.Formats.Png /// public PngInterlaceMode InterlaceMethod { get; } + /// + /// Validates the png header. + /// + /// + /// Thrown if the image does pass validation. + /// + public void Validate() + { + if (!PngConstants.ColorTypes.ContainsKey(this.ColorType)) + { + throw new NotSupportedException("Color type is not supported or not valid."); + } + + if (PngConstants.ColorTypes[this.ColorType].AsSpan().IndexOf(this.BitDepth) == -1) + { + throw new NotSupportedException("Bit depth is not supported or not valid."); + } + + if (this.FilterMethod != 0) + { + throw new NotSupportedException("The png specification only defines 0 as filter method."); + } + + if (this.InterlaceMethod != PngInterlaceMode.None && this.InterlaceMethod != PngInterlaceMode.Adam7) + { + throw new NotSupportedException("The png specification only defines 'None' and 'Adam7' as interlaced methods."); + } + } + /// /// Writes the header to the given buffer. /// From e203fb71212e9774dacc0e13024731c6198dd2f3 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:48:44 -0700 Subject: [PATCH 120/185] Add GetString(ReadOnlySpan polyfill to Encoding --- .../Common/Extensions/EncoderExtensions.cs | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/ImageSharp/Common/Extensions/EncoderExtensions.cs diff --git a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs new file mode 100644 index 0000000000..e6b800e86a --- /dev/null +++ b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs @@ -0,0 +1,34 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +#if !NETCOREAPP2_1 +using System; +using System.Text; + +namespace SixLabors.ImageSharp +{ + /// + /// Extension methods for the type. + /// + internal static unsafe class EncoderExtensions + { + /// + /// Gets a string from the provided buffer data. + /// + /// The encoding. + /// The buffer. + /// The string. + public static string GetString(this Encoding encoding, ReadOnlySpan buffer) + { +#if NETSTANDARD1_1 + return encoding.GetString(buffer.ToArray()); +#else + fixed (byte* bytes = buffer) + { + return encoding.GetString(bytes, buffer.Length); + } +#endif + } + } +} +#endif \ No newline at end of file From 581f7049fd05db502d38715173d7b6ad342c024d Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:51:46 -0700 Subject: [PATCH 121/185] Optimize ReadTextChunk --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 26 ++++++-------------- 1 file changed, 7 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 112dc72623..812175612a 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -3,9 +3,7 @@ using System; using System.Buffers.Binary; -using System.Collections.Generic; using System.IO; -using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; @@ -230,7 +228,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.AssignTransparentMarkers(alpha); break; case PngChunkType.Text: - this.ReadTextChunk(metaData, chunk.Data.Array, chunk.Length); + this.ReadTextChunk(metaData, chunk.Data.Array.AsSpan(0, chunk.Length)); break; case PngChunkType.Exif: if (!this.ignoreMetadata) @@ -297,7 +295,7 @@ namespace SixLabors.ImageSharp.Formats.Png this.SkipChunkDataAndCrc(chunk); break; case PngChunkType.Text: - this.ReadTextChunk(metaData, chunk.Data.Array, chunk.Length); + this.ReadTextChunk(metaData, chunk.Data.Array.AsSpan(0, chunk.Length)); break; case PngChunkType.End: this.isEndChunkReached = true; @@ -896,28 +894,18 @@ namespace SixLabors.ImageSharp.Formats.Png /// Reads a text chunk containing image properties from the data. /// /// The metadata to decode to. - /// The containing data. - /// The maximum length to read. - private void ReadTextChunk(ImageMetaData metadata, byte[] data, int length) + /// The containing the data. + private void ReadTextChunk(ImageMetaData metadata, ReadOnlySpan data) { if (this.ignoreMetadata) { return; } - int zeroIndex = 0; + int zeroIndex = data.IndexOf((byte)0); - for (int i = 0; i < length; i++) - { - if (data[i] == 0) - { - zeroIndex = i; - break; - } - } - - string name = this.textEncoding.GetString(data, 0, zeroIndex); - string value = this.textEncoding.GetString(data, zeroIndex + 1, length - zeroIndex - 1); + string name = this.textEncoding.GetString(data.Slice(0, zeroIndex)); + string value = this.textEncoding.GetString(data.Slice(zeroIndex + 1)); metadata.Properties.Add(new ImageProperty(name, value)); } From 25b6b33cb7f71e9215e6ec9868531127fa6ad527 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 16:56:39 -0700 Subject: [PATCH 122/185] Use Encoding.GetString(ROS) polyfill --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 +- src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs | 13 +------------ 2 files changed, 2 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 812175612a..8344d7b544 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1016,7 +1016,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.crc.Value != chunk.Crc) { - string chunkTypeName = Encoding.UTF8.GetString(chunkType.ToArray(), 0, 4); + string chunkTypeName = Encoding.UTF8.GetString(chunkType); throw new ImageFormatException($"CRC Error. PNG {chunkTypeName} chunk is corrupt!"); } diff --git a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs index 549cb3fe09..5f95499088 100644 --- a/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/MetaData/Profiles/Exif/ExifReader.cs @@ -127,25 +127,14 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Exif private unsafe string ConvertToString(ReadOnlySpan buffer) { - Span nullChar = stackalloc byte[1] { 0 }; - - int nullCharIndex = buffer.IndexOf(nullChar); + int nullCharIndex = buffer.IndexOf((byte)0); if (nullCharIndex > -1) { buffer = buffer.Slice(0, nullCharIndex); } -#if NETSTANDARD1_1 - return Encoding.UTF8.GetString(buffer.ToArray(), 0, buffer.Length); -#elif NETCOREAPP2_1 return Encoding.UTF8.GetString(buffer); -#else - fixed (byte* pointer = &MemoryMarshal.GetReference(buffer)) - { - return Encoding.UTF8.GetString(pointer, buffer.Length); - } -#endif } /// From 94119841bf82f0a0e658439d129d97aa39559c99 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 17:13:22 -0700 Subject: [PATCH 123/185] Add details to PNG header validation errors --- src/ImageSharp/Formats/Png/PngHeader.cs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngHeader.cs b/src/ImageSharp/Formats/Png/PngHeader.cs index 0523502b05..ea43ba96a5 100644 --- a/src/ImageSharp/Formats/Png/PngHeader.cs +++ b/src/ImageSharp/Formats/Png/PngHeader.cs @@ -88,24 +88,25 @@ namespace SixLabors.ImageSharp.Formats.Png /// public void Validate() { - if (!PngConstants.ColorTypes.ContainsKey(this.ColorType)) + if (!PngConstants.ColorTypes.TryGetValue(this.ColorType, out byte[] supportedBitDepths)) { - throw new NotSupportedException("Color type is not supported or not valid."); + throw new NotSupportedException($"Invalid or unsupported color type. Was '{this.ColorType}'."); } - if (PngConstants.ColorTypes[this.ColorType].AsSpan().IndexOf(this.BitDepth) == -1) + if (supportedBitDepths.AsSpan().IndexOf(this.BitDepth) == -1) { - throw new NotSupportedException("Bit depth is not supported or not valid."); + throw new NotSupportedException($"Invalid or unsupported bit depth. Was '{this.BitDepth}'."); } if (this.FilterMethod != 0) { - throw new NotSupportedException("The png specification only defines 0 as filter method."); + throw new NotSupportedException($"Invalid filter method. Expected 0. Was '{this.FilterMethod}'."); } + // The png specification only defines 'None' and 'Adam7' as interlaced methods. if (this.InterlaceMethod != PngInterlaceMode.None && this.InterlaceMethod != PngInterlaceMode.Adam7) { - throw new NotSupportedException("The png specification only defines 'None' and 'Adam7' as interlaced methods."); + throw new NotSupportedException($"Invalid interlace method. Expected 'None' or 'Adam7'. Was '{this.InterlaceMethod}'."); } } From 96ad14fb6e6af49261882a45cb25d68f72e1df9d Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 17:53:07 -0700 Subject: [PATCH 124/185] Breakout the PngPhysicalChunkData conversion and encoding functions from the encoder --- .../Png/Chunks/PngPhysicalChunkData.cs | 93 +++++++++++++++++++ src/ImageSharp/Formats/Png/PngEncoderCore.cs | 42 +-------- 2 files changed, 95 insertions(+), 40 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/Chunks/PngPhysicalChunkData.cs diff --git a/src/ImageSharp/Formats/Png/Chunks/PngPhysicalChunkData.cs b/src/ImageSharp/Formats/Png/Chunks/PngPhysicalChunkData.cs new file mode 100644 index 0000000000..39a9676b63 --- /dev/null +++ b/src/ImageSharp/Formats/Png/Chunks/PngPhysicalChunkData.cs @@ -0,0 +1,93 @@ +using System; +using System.Buffers.Binary; +using SixLabors.ImageSharp.Common.Helpers; +using SixLabors.ImageSharp.MetaData; + +namespace SixLabors.ImageSharp.Formats.Png +{ + /// + /// The pHYs chunk specifies the intended pixel size or aspect ratio for display of the image. + /// + internal readonly struct PngPhysicalChunkData + { + public const int Size = 9; + + public PngPhysicalChunkData(uint x, uint y, byte unitSpecifier) + { + this.XAxisPixelsPerUnit = x; + this.YAxisPixelsPerUnit = y; + this.UnitSpecifier = unitSpecifier; + } + + /// + /// Gets the number of pixels per unit on the X axis. + /// + public uint XAxisPixelsPerUnit { get; } + + /// + /// Gets the number of pixels per unit on the Y axis. + /// + public uint YAxisPixelsPerUnit { get; } + + /// + /// Gets the unit specifier. + /// 0: unit is unknown + /// 1: unit is the meter + /// When the unit specifier is 0, the pHYs chunk defines pixel aspect ratio only; the actual size of the pixels remains unspecified. + /// + public byte UnitSpecifier { get; } + + /// + /// Constructs the PngPhysicalChunkData from the provided metadata. + /// If the resolution units are not in meters, they are automatically convereted. + /// + /// The metadata. + /// The constructed PngPhysicalChunkData instance. + public static PngPhysicalChunkData FromMetadata(ImageMetaData meta) + { + byte unitSpecifier = 0; + uint x; + uint y; + + switch (meta.ResolutionUnits) + { + case PixelResolutionUnit.AspectRatio: + unitSpecifier = 0; // Unspecified + x = (uint)Math.Round(meta.HorizontalResolution); + y = (uint)Math.Round(meta.VerticalResolution); + break; + + case PixelResolutionUnit.PixelsPerInch: + unitSpecifier = 1; // Per meter + x = (uint)Math.Round(UnitConverter.InchToMeter(meta.HorizontalResolution)); + y = (uint)Math.Round(UnitConverter.InchToMeter(meta.VerticalResolution)); + break; + + case PixelResolutionUnit.PixelsPerCentimeter: + unitSpecifier = 1; // Per meter + x = (uint)Math.Round(UnitConverter.CmToMeter(meta.HorizontalResolution)); + y = (uint)Math.Round(UnitConverter.CmToMeter(meta.VerticalResolution)); + break; + + default: + unitSpecifier = 1; // Per meter + x = (uint)Math.Round(meta.HorizontalResolution); + y = (uint)Math.Round(meta.VerticalResolution); + break; + } + + return new PngPhysicalChunkData(x, y, unitSpecifier); + } + + /// + /// Writes the data to the given buffer. + /// + /// The buffer. + public void WriteTo(Span buffer) + { + BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(0, 4), this.XAxisPixelsPerUnit); + BinaryPrimitives.WriteUInt32BigEndian(buffer.Slice(4, 4), this.YAxisPixelsPerUnit); + buffer[8] = this.UnitSpecifier; + } + } +} diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 525cc8bd1c..7f3c9945ad 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -674,47 +674,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image meta data. private void WritePhysicalChunk(Stream stream, ImageMetaData meta) { - // The pHYs chunk specifies the intended pixel size or aspect ratio for display of the image. It contains: - // Pixels per unit, X axis: 4 bytes (unsigned integer) - // Pixels per unit, Y axis: 4 bytes (unsigned integer) - // Unit specifier: 1 byte - // - // The following values are legal for the unit specifier: - // 0: unit is unknown - // 1: unit is the meter - // - // When the unit specifier is 0, the pHYs chunk defines pixel aspect ratio only; the actual size of the pixels remains unspecified. - Span hResolution = this.chunkDataBuffer.AsSpan(0, 4); - Span vResolution = this.chunkDataBuffer.AsSpan(4, 4); - - switch (meta.ResolutionUnits) - { - case PixelResolutionUnit.AspectRatio: - this.chunkDataBuffer[8] = 0; - BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(meta.HorizontalResolution)); - BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(meta.VerticalResolution)); - break; - - case PixelResolutionUnit.PixelsPerInch: - this.chunkDataBuffer[8] = 1; // Per meter - BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(UnitConverter.InchToMeter(meta.HorizontalResolution))); - BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(UnitConverter.InchToMeter(meta.VerticalResolution))); - break; - - case PixelResolutionUnit.PixelsPerCentimeter: - this.chunkDataBuffer[8] = 1; // Per meter - BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(UnitConverter.CmToMeter(meta.HorizontalResolution))); - BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(UnitConverter.CmToMeter(meta.VerticalResolution))); - break; - - default: - this.chunkDataBuffer[8] = 1; // Per meter - BinaryPrimitives.WriteInt32BigEndian(hResolution, (int)Math.Round(meta.HorizontalResolution)); - BinaryPrimitives.WriteInt32BigEndian(vResolution, (int)Math.Round(meta.VerticalResolution)); - break; - } + PngPhysicalChunkData.FromMetadata(meta).WriteTo(this.chunkDataBuffer); - this.WriteChunk(stream, PngChunkType.Physical, this.chunkDataBuffer, 0, 9); + this.WriteChunk(stream, PngChunkType.Physical, this.chunkDataBuffer, 0, PngPhysicalChunkData.Size); } /// From 05a0ca20d902f08a587da9e85e48620b0d3dcd8d Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 18:00:33 -0700 Subject: [PATCH 125/185] Move PhysicalChunkData to Chunks namespace --- .../{PngPhysicalChunkData.cs => PhysicalChunkData.cs} | 8 ++++---- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 5 ++--- 2 files changed, 6 insertions(+), 7 deletions(-) rename src/ImageSharp/Formats/Png/Chunks/{PngPhysicalChunkData.cs => PhysicalChunkData.cs} (93%) diff --git a/src/ImageSharp/Formats/Png/Chunks/PngPhysicalChunkData.cs b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs similarity index 93% rename from src/ImageSharp/Formats/Png/Chunks/PngPhysicalChunkData.cs rename to src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs index 39a9676b63..c1c151611a 100644 --- a/src/ImageSharp/Formats/Png/Chunks/PngPhysicalChunkData.cs +++ b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs @@ -3,16 +3,16 @@ using System.Buffers.Binary; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.MetaData; -namespace SixLabors.ImageSharp.Formats.Png +namespace SixLabors.ImageSharp.Formats.Png.Chunks { /// /// The pHYs chunk specifies the intended pixel size or aspect ratio for display of the image. /// - internal readonly struct PngPhysicalChunkData + internal readonly struct PhysicalChunkData { public const int Size = 9; - public PngPhysicalChunkData(uint x, uint y, byte unitSpecifier) + public PhysicalChunkData(uint x, uint y, byte unitSpecifier) { this.XAxisPixelsPerUnit = x; this.YAxisPixelsPerUnit = y; @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The metadata. /// The constructed PngPhysicalChunkData instance. - public static PngPhysicalChunkData FromMetadata(ImageMetaData meta) + public static PhysicalChunkData FromMetadata(ImageMetaData meta) { byte unitSpecifier = 0; uint x; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7f3c9945ad..a86d8173cb 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -9,7 +9,6 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Memory; @@ -674,9 +673,9 @@ namespace SixLabors.ImageSharp.Formats.Png /// The image meta data. private void WritePhysicalChunk(Stream stream, ImageMetaData meta) { - PngPhysicalChunkData.FromMetadata(meta).WriteTo(this.chunkDataBuffer); + PhysicalChunkData.FromMetadata(meta).WriteTo(this.chunkDataBuffer); - this.WriteChunk(stream, PngChunkType.Physical, this.chunkDataBuffer, 0, PngPhysicalChunkData.Size); + this.WriteChunk(stream, PngChunkType.Physical, this.chunkDataBuffer, 0, PhysicalChunkData.Size); } /// From 66c3f93890d40c12881522ad97e16099cf3a7060 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 1 Oct 2018 18:04:32 -0700 Subject: [PATCH 126/185] Add Parse method to PhysicalChunkData --- .../Formats/Png/Chunks/PhysicalChunkData.cs | 16 ++++++++++++- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 23 +++++-------------- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 1 + 3 files changed, 22 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs index c1c151611a..07fc688d50 100644 --- a/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs +++ b/src/ImageSharp/Formats/Png/Chunks/PhysicalChunkData.cs @@ -37,6 +37,20 @@ namespace SixLabors.ImageSharp.Formats.Png.Chunks /// public byte UnitSpecifier { get; } + /// + /// Parses the PhysicalChunkData from the given buffer. + /// + /// The data buffer. + /// The parsed PhysicalChunkData. + public static PhysicalChunkData Parse(ReadOnlySpan data) + { + uint hResolution = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(0, 4)); + uint vResolution = BinaryPrimitives.ReadUInt32BigEndian(data.Slice(4, 4)); + byte unit = data[8]; + + return new PhysicalChunkData(hResolution, vResolution, unit); + } + /// /// Constructs the PngPhysicalChunkData from the provided metadata. /// If the resolution units are not in meters, they are automatically convereted. @@ -76,7 +90,7 @@ namespace SixLabors.ImageSharp.Formats.Png.Chunks break; } - return new PngPhysicalChunkData(x, y, unitSpecifier); + return new PhysicalChunkData(x, y, unitSpecifier); } /// diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 8344d7b544..8401f4e98f 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -8,6 +8,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Memory; @@ -376,26 +377,14 @@ namespace SixLabors.ImageSharp.Formats.Png /// The data containing physical data. private void ReadPhysicalChunk(ImageMetaData metadata, ReadOnlySpan data) { - // The pHYs chunk specifies the intended pixel size or aspect ratio for display of the image. It contains: - // Pixels per unit, X axis: 4 bytes (unsigned integer) - // Pixels per unit, Y axis: 4 bytes (unsigned integer) - // Unit specifier: 1 byte - // - // The following values are legal for the unit specifier: - // 0: unit is unknown - // 1: unit is the meter - // - // When the unit specifier is 0, the pHYs chunk defines pixel aspect ratio only; the actual size of the pixels remains unspecified. - int hResolution = BinaryPrimitives.ReadInt32BigEndian(data.Slice(0, 4)); - int vResolution = BinaryPrimitives.ReadInt32BigEndian(data.Slice(4, 4)); - byte unit = data[8]; - - metadata.ResolutionUnits = unit == byte.MinValue + var physicalChunk = PhysicalChunkData.Parse(data); + + metadata.ResolutionUnits = physicalChunk.UnitSpecifier == byte.MinValue ? PixelResolutionUnit.AspectRatio : PixelResolutionUnit.PixelsPerMeter; - metadata.HorizontalResolution = hResolution; - metadata.VerticalResolution = vResolution; + metadata.HorizontalResolution = physicalChunk.XAxisPixelsPerUnit; + metadata.VerticalResolution = physicalChunk.YAxisPixelsPerUnit; } /// diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index a86d8173cb..a46d83707e 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -9,6 +9,7 @@ using System.Linq; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.Formats.Png.Zlib; using SixLabors.ImageSharp.Memory; From 09be4d225c222ae84c952a2ca67fa2c2b5bd4d29 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 16:12:46 +0100 Subject: [PATCH 127/185] Remove duplicate Adaption checks and reduce allocations. --- .../Conversion/ColorSpaceConverter.Adapt.cs | 65 +++++++++---------- .../Conversion/ColorSpaceConverter.CieLab.cs | 9 +-- .../Conversion/ColorSpaceConverter.CieLch.cs | 2 +- .../ColorSpaceConverter.CieLchuv.cs | 2 +- .../Conversion/ColorSpaceConverter.CieLuv.cs | 12 +--- .../Conversion/ColorSpaceConverter.CieXyz.cs | 22 ++----- .../ColorSpaceConverter.HunterLab.cs | 7 +- .../ColorSpaceConverter.LinearRgb.cs | 24 +------ .../Conversion/ColorSpaceConverter.cs | 21 +++--- 9 files changed, 55 insertions(+), 109 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs index 29d4fca5e4..892c0d5e38 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Adapt.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -16,12 +15,26 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// Target white point is . /// /// The color to adapt - /// The white point to adapt for + /// The source white point. /// The adapted color - public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint) + public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint) => this.Adapt(color, sourceWhitePoint, this.whitePoint); + + /// + /// Performs chromatic adaptation of given color. + /// Target white point is . + /// + /// The color to adapt + /// The source white point. + /// The target white point. + /// The adapted color + public CieXyz Adapt(in CieXyz color, in CieXyz sourceWhitePoint, in CieXyz targetWhitePoint) { - this.CheckChromaticAdaptation(); - return this.chromaticAdaptation.Transform(color, sourceWhitePoint, this.whitePoint); + if (!this.performChromaticAdaptation || sourceWhitePoint.Equals(targetWhitePoint)) + { + return color; + } + + return this.chromaticAdaptation.Transform(color, sourceWhitePoint, targetWhitePoint); } /// @@ -31,9 +44,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public CieLab Adapt(in CieLab color) { - this.CheckChromaticAdaptation(); - - if (color.WhitePoint.Equals(this.targetLabWhitePoint)) + if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint)) { return color; } @@ -49,9 +60,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public CieLch Adapt(in CieLch color) { - this.CheckChromaticAdaptation(); - - if (color.WhitePoint.Equals(this.targetLabWhitePoint)) + if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint)) { return color; } @@ -67,9 +76,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public CieLchuv Adapt(in CieLchuv color) { - this.CheckChromaticAdaptation(); - - if (color.WhitePoint.Equals(this.targetLabWhitePoint)) + if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLabWhitePoint)) { return color; } @@ -85,9 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public CieLuv Adapt(in CieLuv color) { - this.CheckChromaticAdaptation(); - - if (color.WhitePoint.Equals(this.targetLuvWhitePoint)) + if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetLuvWhitePoint)) { return color; } @@ -103,9 +108,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public HunterLab Adapt(in HunterLab color) { - this.CheckChromaticAdaptation(); - - if (color.WhitePoint.Equals(this.targetHunterLabWhitePoint)) + if (!this.performChromaticAdaptation || color.WhitePoint.Equals(this.targetHunterLabWhitePoint)) { return color; } @@ -121,9 +124,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public LinearRgb Adapt(in LinearRgb color) { - this.CheckChromaticAdaptation(); - - if (color.WorkingSpace.Equals(this.targetRgbWorkingSpace)) + if (!this.performChromaticAdaptation || color.WorkingSpace.Equals(this.targetRgbWorkingSpace)) { return color; } @@ -136,8 +137,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz adapted = this.chromaticAdaptation.Transform(unadapted, color.WorkingSpace.WhitePoint, this.targetRgbWorkingSpace.WhitePoint); // Conversion back to RGB - CieXyzToLinearRgbConverter converterToRGB = this.GetCieXyxToLinearRgbConverter(this.targetRgbWorkingSpace); - return converterToRGB.Convert(adapted); + return this.cieXyzToLinearRgbConverter.Convert(adapted); } /// @@ -147,19 +147,14 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The adapted color public Rgb Adapt(in Rgb color) { - var linearInput = this.ToLinearRgb(color); - LinearRgb linearOutput = this.Adapt(linearInput); - return this.ToRgb(linearOutput); - } - - private void CheckChromaticAdaptation() - { - const string NoAdapterMessage = "Cannot perform chromatic adaptation, provide a chromatic adaptation method and white point."; - if (!this.performChromaticAdaptation) { - throw new InvalidOperationException(NoAdapterMessage); + return color; } + + var linearInput = this.ToLinearRgb(color); + LinearRgb linearOutput = this.Adapt(linearInput); + return this.ToRgb(linearOutput); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index d971ad1331..e79f51211c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -28,11 +28,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion // Conversion (perserving white point) CieLab unadapted = CieLchToCieLabConverter.Convert(color); - if (!this.performChromaticAdaptation) - { - return unadapted; - } - // Adaptation return this.Adapt(unadapted); } @@ -165,9 +160,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLab ToCieLab(in CieXyz color) { // Adaptation - CieXyz adapted = this.performLabChromaticAdaptation - ? this.chromaticAdaptation.Transform(color, this.whitePoint, this.targetLabWhitePoint) - : color; + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLabWhitePoint); // Conversion return this.cieXyzToCieLabConverter.Convert(adapted); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index b7b29109d8..601a874d51 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLch ToCieLch(in CieLab color) { // Adaptation - CieLab adapted = this.performChromaticAdaptation ? this.Adapt(color) : color; + CieLab adapted = this.Adapt(color); // Conversion return CieLabToCieLchConverter.Convert(adapted); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 1f831984af..3d77b0076a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLchuv ToCieLchuv(in CieLuv color) { // Adaptation - CieLuv adapted = this.performChromaticAdaptation ? this.Adapt(color) : color; + CieLuv adapted = this.Adapt(color); // Conversion return CieLuvToCieLchuvConverter.Convert(adapted); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index b4d9ce08ed..b58c838106 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -89,11 +89,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion // Conversion (perserving white point) CieLuv unadapted = CieLchuvToCieLuvConverter.Convert(color); - if (!this.performChromaticAdaptation) - { - return unadapted; - } - // Adaptation return this.Adapt(unadapted); } @@ -159,13 +154,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLuv ToCieLuv(in CieXyz color) { // Adaptation - CieXyz adapted = !this.whitePoint.Equals(this.targetLabWhitePoint) && this.performChromaticAdaptation - ? this.chromaticAdaptation.Transform(color, this.whitePoint, this.targetLabWhitePoint) - : color; + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLabWhitePoint); // Conversion - var converter = new CieXyzToCieLuvConverter(this.targetLuvWhitePoint); - return converter.Convert(adapted); + return this.cieXyzToCieLuvConverter.Convert(adapted); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 20aa359ca8..2d70c83d67 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -32,11 +32,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz unadapted = CieLabToCieXyzConverter.Convert(color); // Adaptation - CieXyz adapted = color.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation - ? unadapted - : this.Adapt(unadapted, color.WhitePoint); - - return adapted; + return this.Adapt(unadapted, color.WhitePoint); } /// @@ -141,11 +137,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz unadapted = CieLuvToCieXyzConverter.Convert(color); // Adaptation - CieXyz adapted = color.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation - ? unadapted - : this.Adapt(unadapted, color.WhitePoint); - - return adapted; + return this.Adapt(unadapted, color.WhitePoint); } /// @@ -314,11 +306,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz unadapted = HunterLabToCieXyzConverter.Convert(color); // Adaptation - CieXyz adapted = color.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation - ? unadapted - : this.Adapt(unadapted, color.WhitePoint); - - return adapted; + return this.Adapt(unadapted, color.WhitePoint); } /// @@ -354,9 +342,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion CieXyz unadapted = converter.Convert(color); // Adaptation - return color.WorkingSpace.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation - ? unadapted - : this.Adapt(unadapted, color.WorkingSpace.WhitePoint); + return this.Adapt(unadapted, color.WorkingSpace.WhitePoint); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index bb3e1e4cee..ddc225d1de 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -4,7 +4,6 @@ using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion { @@ -181,12 +180,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public HunterLab ToHunterLab(in CieXyz color) { // Adaptation - CieXyz adapted = !this.whitePoint.Equals(this.targetHunterLabWhitePoint) && this.performChromaticAdaptation - ? this.chromaticAdaptation.Transform(color, this.whitePoint, this.targetHunterLabWhitePoint) - : color; + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetHunterLabWhitePoint); // Conversion - return new CieXyzToHunterLabConverter(this.targetHunterLabWhitePoint).Convert(adapted); + return this.cieXyzToHunterLabConverter.Convert(adapted); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index f95350b298..f230c0e6fd 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -15,8 +15,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion { private static readonly RgbToLinearRgbConverter RgbToLinearRgbConverter = new RgbToLinearRgbConverter(); - private CieXyzToLinearRgbConverter cieXyzToLinearRgbConverter; - /// /// Converts a into a /// @@ -185,13 +183,10 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public LinearRgb ToLinearRgb(in CieXyz color) { // Adaptation - CieXyz adapted = this.targetRgbWorkingSpace.WhitePoint.Equals(this.whitePoint) || !this.performChromaticAdaptation - ? color - : this.chromaticAdaptation.Transform(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetRgbWorkingSpace.WhitePoint); // Conversion - CieXyzToLinearRgbConverter xyzConverter = this.GetCieXyxToLinearRgbConverter(this.targetRgbWorkingSpace); - return xyzConverter.Convert(adapted); + return this.cieXyzToLinearRgbConverter.Convert(adapted); } /// @@ -438,20 +433,5 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion dp = this.ToLinearRgb(sp); } } - - /// - /// Gets the correct converter for the given rgb working space. - /// - /// The target working space - /// The - private CieXyzToLinearRgbConverter GetCieXyxToLinearRgbConverter(RgbWorkingSpace workingSpace) - { - if (this.cieXyzToLinearRgbConverter != null && this.cieXyzToLinearRgbConverter.TargetWorkingSpace.Equals(workingSpace)) - { - return this.cieXyzToLinearRgbConverter; - } - - return this.cieXyzToLinearRgbConverter = new CieXyzToLinearRgbConverter(workingSpace); - } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index bf28780dc4..8fd6ca449e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -12,18 +12,19 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public partial class ColorSpaceConverter { // Options. + private Matrix4x4 lmsAdaptationMatrix; private CieXyz whitePoint; private CieXyz targetLuvWhitePoint; private CieXyz targetLabWhitePoint; private CieXyz targetHunterLabWhitePoint; - private RgbWorkingSpace targetRgbWorkingSpace; - private IChromaticAdaptation chromaticAdaptation; - private bool performChromaticAdaptation; - private bool performLabChromaticAdaptation; - private Matrix4x4 lmsAdaptationMatrix; - - private CieXyzAndLmsConverter cieXyzAndLmsConverter; - private CieXyzToCieLabConverter cieXyzToCieLabConverter; + private readonly RgbWorkingSpace targetRgbWorkingSpace; + private readonly IChromaticAdaptation chromaticAdaptation; + private readonly bool performChromaticAdaptation; + private readonly CieXyzAndLmsConverter cieXyzAndLmsConverter; + private readonly CieXyzToCieLabConverter cieXyzToCieLabConverter; + private readonly CieXyzToCieLuvConverter cieXyzToCieLuvConverter; + private readonly CieXyzToHunterLabConverter cieXyzToHunterLabConverter; + private readonly CieXyzToLinearRgbConverter cieXyzToLinearRgbConverter; /// /// Initializes a new instance of the class. @@ -47,11 +48,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion this.targetRgbWorkingSpace = options.TargetRgbWorkingSpace; this.chromaticAdaptation = options.ChromaticAdaptation; this.performChromaticAdaptation = this.chromaticAdaptation != null; - this.performLabChromaticAdaptation = !this.whitePoint.Equals(this.targetLabWhitePoint) && this.performChromaticAdaptation; this.lmsAdaptationMatrix = options.LmsAdaptationMatrix; this.cieXyzAndLmsConverter = new CieXyzAndLmsConverter(this.lmsAdaptationMatrix); this.cieXyzToCieLabConverter = new CieXyzToCieLabConverter(this.targetLabWhitePoint); + this.cieXyzToCieLuvConverter = new CieXyzToCieLuvConverter(this.targetLuvWhitePoint); + this.cieXyzToHunterLabConverter = new CieXyzToHunterLabConverter(this.targetHunterLabWhitePoint); + this.cieXyzToLinearRgbConverter = new CieXyzToLinearRgbConverter(this.targetRgbWorkingSpace); } } } \ No newline at end of file From 8a6d032022c2ac4e380d36c6c45554708caf0792 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 17:20:08 +0100 Subject: [PATCH 128/185] Fix colorspace string representation tests. --- src/ImageSharp/ColorSpaces/CieLch.cs | 2 +- src/ImageSharp/ColorSpaces/CieLchuv.cs | 2 +- src/ImageSharp/ColorSpaces/CieLuv.cs | 2 +- .../CieXyChromaticityCoordinates.cs | 2 +- src/ImageSharp/ColorSpaces/CieXyy.cs | 2 +- src/ImageSharp/ColorSpaces/CieXyz.cs | 2 +- src/ImageSharp/ColorSpaces/Cmyk.cs | 2 +- src/ImageSharp/ColorSpaces/Hsl.cs | 2 +- src/ImageSharp/ColorSpaces/Hsv.cs | 2 +- src/ImageSharp/ColorSpaces/HunterLab.cs | 2 +- src/ImageSharp/ColorSpaces/LinearRgb.cs | 2 +- src/ImageSharp/ColorSpaces/Lms.cs | 2 +- src/ImageSharp/ColorSpaces/Rgb.cs | 2 +- src/ImageSharp/ColorSpaces/YCbCr.cs | 2 +- .../Conversion/StringRepresentationTests.cs | 65 ------------------- .../Colorspaces/StringRepresentationTests.cs | 65 +++++++++++++++++++ 16 files changed, 79 insertions(+), 79 deletions(-) delete mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/StringRepresentationTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index 68fe124a6a..47eb53e770 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLch [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}]"; + public override string ToString() => $"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"; /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index e37f7fa20d..a92cad2a3d 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -127,7 +127,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLchuv [ L={this.L:#0.##}, C={this.C:#0.##}, H={this.H:#0.##}"; + public override string ToString() => $"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"; /// public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index 10ff7287ed..c8639c8162 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -130,7 +130,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLuv [ L={this.L:#0.##}, U={this.U:#0.##}, V={this.V:#0.##} ]"; + public override string ToString() => $"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})"; /// public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs index 64ba44878c..06aaafb553 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs @@ -67,7 +67,7 @@ namespace SixLabors.ImageSharp.ColorSpaces public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode()); /// - public override string ToString() => $"CieXyChromaticityCoordinates [ X={this.X:#0.##}, Y={this.Y:#0.##}]"; + public override string ToString() => $"CieXyChromaticityCoordinates({this.X:#0.##}, {this.Y:#0.##})"; /// public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index 2b40c30393..e8e129df90 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieXyy [ X={this.X:#0.##}, Y={this.Y:#0.##}, Yl={this.Yl:#0.##} ]"; + public override string ToString() => $"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})"; /// public override bool Equals(object obj) => obj is CieXyy other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index b992a7a3e6..8995d3eeba 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieXyz [ X={this.X:#0.##}, Y={this.Y:#0.##}, Z={this.Z:#0.##} ]"; + public override string ToString() => $"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})"; /// public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index ea3c0b047b..78153eced8 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Cmyk [ C={this.C:#0.##}, M={this.M:#0.##}, Y={this.Y:#0.##}, K={this.K:#0.##}]"; + public override string ToString() => $"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})"; /// public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index 1110241675..2197b8504d 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -94,7 +94,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Hsl [ H={this.H:#0.##}, S={this.S:#0.##}, L={this.L:#0.##} ]"; + public override string ToString() => $"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})"; /// public override bool Equals(object obj) => obj is Hsl other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index fdd34b1b43..b10444aff4 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -92,7 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Hsv [ H={this.H:#0.##}, S={this.S:#0.##}, V={this.V:#0.##} ]"; + public override string ToString() => $"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})"; /// public override bool Equals(object obj) => obj is Hsv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index 9c7b456641..8771081d5b 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -126,7 +126,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"HunterLab [ L={this.L:#0.##}, A={this.A:#0.##}, B={this.B:#0.##}]"; + public override string ToString() => $"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"; /// public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index d055afc808..14ff919c19 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"LinearRgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; + public override string ToString() => $"LinearRgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"; /// public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index becfea3415..2ad7c5a10a 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Lms [ L={this.L:#0.##}, M={this.M:#0.##}, S={this.S:#0.##} ]"; + public override string ToString() => $"Lms({this.L:#0.##}, {this.M:#0.##}, {this.S:#0.##})"; /// public override bool Equals(object obj) => obj is Lms other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index e75de117c0..39fe534535 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Rgb [ R={this.R:#0.##}, G={this.G:#0.##}, B={this.B:#0.##} ]"; + public override string ToString() => $"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"; /// public override bool Equals(object obj) => obj is Rgb other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index a1514505a3..6b94f4a4a8 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"YCbCr [ Y={this.Y}, Cb={this.Cb}, Cr={this.Cr} ]"; + public override string ToString() => $"YCbCr({this.Y}, {this.Cb}, {this.Cr})"; /// public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/StringRepresentationTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/StringRepresentationTests.cs deleted file mode 100644 index 580e6cb4ec..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/StringRepresentationTests.cs +++ /dev/null @@ -1,65 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion -{ - public class StringRepresentationTests - { - private static readonly Vector3 one = new Vector3(1); - private static readonly Vector3 zero = new Vector3(0); - private static readonly Vector3 random = new Vector3(42.4F, 94.5F, 83.4F); - - public static readonly TheoryData TestData = new TheoryData - { - { new CieLab(zero), "CieLab(0,0,0)" }, - { new CieLch(zero), "CieLch(0,0,0)" }, - { new CieLchuv(zero), "CieLchuv(0,0,0)" }, - { new CieLuv(zero), "CieLuv(0,0,0)" }, - { new CieXyz(zero), "CieXyz(0,0,0)" }, - { new CieXyy(zero), "CieXyy(0,0,0)" }, - { new HunterLab(zero), "HunterLab(0,0,0)" }, - { new Lms(zero), "Lms(0,0,0)" }, - { new LinearRgb(zero), "LinearRgb(0,0,0)" }, - { new Rgb(zero), "Rgb(0,0,0)" }, - { new Hsl(zero), "Hsl(0,0,0)" }, - { new Hsv(zero), "Hsv(0,0,0)" }, - { new YCbCr(zero), "YCbCr(0,0,0)" }, - - { new CieLab(one), "CieLab(1,1,1)" }, - { new CieLch(one), "CieLch(1,1,1)" }, - { new CieLchuv(one), "CieLchuv(1,1,1)" }, - { new CieLuv(one), "CieLuv(1,1,1)" }, - { new CieXyz(one), "CieXyz(1,1,1)" }, - { new CieXyy(one), "CieXyy(1,1,1)" }, - { new HunterLab(one), "HunterLab(1,1,1)" }, - { new Lms(one), "Lms(1,1,1)" }, - { new LinearRgb(one), "LinearRgb(1,1,1)" }, - { new Rgb(one), "Rgb(1,1,1)" }, - { new Hsl(one), "Hsl(1,1,1)" }, - { new Hsv(one), "Hsv(1,1,1)" }, - { new YCbCr(one), "YCbCr(1,1,1)" }, - - { new CieLab(random), "CieLab(42.4,94.5,83.4)" }, - { new CieLch(random), "CieLch(42.4,94.5,83.4)" }, - { new CieLchuv(random), "CieLchuv(42.4,94.5,83.4)" }, - { new CieLuv(random), "CieLuv(42.4,94.5,83.4)" }, - { new CieXyz(random), "CieXyz(42.4,94.5,83.4)" }, - { new CieXyy(random), "CieXyy(42.4,94.5,83.4)" }, - { new HunterLab(random), "HunterLab(42.4,94.5,83.4)" }, - { new Lms(random), "Lms(42.4,94.5,83.4)" }, - { new LinearRgb(random), "LinearRgb(1,1,1)" }, // clamping to 1 is expected - { new Rgb(random), "Rgb(1,1,1)" }, // clamping to 1 is expected - { new Hsl(random), "Hsl(42.4,1,1)" }, // clamping to 1 is expected - { new Hsv(random), "Hsv(42.4,1,1)" }, // clamping to 1 is expected - { new YCbCr(random), "YCbCr(42.4,94.5,83.4)" }, - }; - - [Theory] - [MemberData(nameof(TestData))] - public void StringRepresentationsAreCorrect(object color, string text) => Assert.Equal(text, color.ToString()); - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs b/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs new file mode 100644 index 0000000000..44b02f1657 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs @@ -0,0 +1,65 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + public class StringRepresentationTests + { + private static readonly Vector3 one = new Vector3(1); + private static readonly Vector3 zero = new Vector3(0); + private static readonly Vector3 random = new Vector3(42.4F, 94.5F, 83.4F); + + public static readonly TheoryData TestData = new TheoryData + { + { new CieLab(zero), "CieLab(0, 0, 0)" }, + { new CieLch(zero), "CieLch(0, 0, 0)" }, + { new CieLchuv(zero), "CieLchuv(0, 0, 0)" }, + { new CieLuv(zero), "CieLuv(0, 0, 0)" }, + { new CieXyz(zero), "CieXyz(0, 0, 0)" }, + { new CieXyy(zero), "CieXyy(0, 0, 0)" }, + { new HunterLab(zero), "HunterLab(0, 0, 0)" }, + { new Lms(zero), "Lms(0, 0, 0)" }, + { new LinearRgb(zero), "LinearRgb(0, 0, 0)" }, + { new Rgb(zero), "Rgb(0, 0, 0)" }, + { new Hsl(zero), "Hsl(0, 0, 0)" }, + { new Hsv(zero), "Hsv(0, 0, 0)" }, + { new YCbCr(zero), "YCbCr(0, 0, 0)" }, + + { new CieLab(one), "CieLab(1, 1, 1)" }, + { new CieLch(one), "CieLch(1, 1, 1)" }, + { new CieLchuv(one), "CieLchuv(1, 1, 1)" }, + { new CieLuv(one), "CieLuv(1, 1, 1)" }, + { new CieXyz(one), "CieXyz(1, 1, 1)" }, + { new CieXyy(one), "CieXyy(1, 1, 1)" }, + { new HunterLab(one), "HunterLab(1, 1, 1)" }, + { new Lms(one), "Lms(1, 1, 1)" }, + { new LinearRgb(one), "LinearRgb(1, 1, 1)" }, + { new Rgb(one), "Rgb(1, 1, 1)" }, + { new Hsl(one), "Hsl(1, 1, 1)" }, + { new Hsv(one), "Hsv(1, 1, 1)" }, + { new YCbCr(one), "YCbCr(1, 1, 1)" }, + + { new CieLab(random), "CieLab(42.4, 94.5, 83.4)" }, + { new CieLch(random), "CieLch(42.4, 94.5, 83.4)" }, + { new CieLchuv(random), "CieLchuv(42.4, 94.5, 83.4)" }, + { new CieLuv(random), "CieLuv(42.4, 94.5, 83.4)" }, + { new CieXyz(random), "CieXyz(42.4, 94.5, 83.4)" }, + { new CieXyy(random), "CieXyy(42.4, 94.5, 83.4)" }, + { new HunterLab(random), "HunterLab(42.4, 94.5, 83.4)" }, + { new Lms(random), "Lms(42.4, 94.5, 83.4)" }, + { new LinearRgb(random), "LinearRgb(1, 1, 1)" }, // clamping to 1 is expected + { new Rgb(random), "Rgb(1, 1, 1)" }, // clamping to 1 is expected + { new Hsl(random), "Hsl(42.4, 1, 1)" }, // clamping to 1 is expected + { new Hsv(random), "Hsv(42.4, 1, 1)" }, // clamping to 1 is expected + { new YCbCr(random), "YCbCr(42.4, 94.5, 83.4)" }, + }; + + [Theory] + [MemberData(nameof(TestData))] + public void StringRepresentationsAreCorrect(object color, string text) => Assert.Equal(text, color.ToString()); + } +} \ No newline at end of file From 02f7339ee6111d80ea74a1c5cdd26fbbd03f2205 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 20:16:44 +0100 Subject: [PATCH 129/185] Add clamping and more struct tests --- src/ImageSharp/ColorSpaces/CieLab.cs | 12 +- src/ImageSharp/ColorSpaces/CieLch.cs | 11 +- src/ImageSharp/ColorSpaces/CieLchuv.cs | 13 +- src/ImageSharp/ColorSpaces/CieLuv.cs | 9 +- src/ImageSharp/ColorSpaces/CieXyz.cs | 4 - src/ImageSharp/ColorSpaces/Cmyk.cs | 5 +- src/ImageSharp/ColorSpaces/Hsl.cs | 8 +- src/ImageSharp/ColorSpaces/Hsv.cs | 8 +- src/ImageSharp/ColorSpaces/HunterLab.cs | 5 +- src/ImageSharp/ColorSpaces/LinearRgb.cs | 5 +- src/ImageSharp/ColorSpaces/Lms.cs | 4 +- src/ImageSharp/ColorSpaces/Rgb.cs | 12 +- src/ImageSharp/ColorSpaces/YCbCr.cs | 8 +- .../Common/Extensions/ComparableExtensions.cs | 34 +--- .../Colorspaces/CieLabTests.cs | 43 +++++ .../Colorspaces/CieLchTests.cs | 39 +++++ .../Colorspaces/CieLchuvTests.cs | 39 +++++ .../Colorspaces/CieLuvTests.cs | 39 +++++ .../Colorspaces/CieXyyTests.cs | 39 +++++ .../Colorspaces/CieXyzTests.cs | 39 +++++ .../ImageSharp.Tests/Colorspaces/CmykTests.cs | 41 +++++ .../Colorspaces/ColorSpaceEqualityTests.cs | 162 ------------------ .../Conversion/CieXyzAndLmsConversionTest.cs | 11 ++ .../ImageSharp.Tests/Colorspaces/HslTests.cs | 39 +++++ .../ImageSharp.Tests/Colorspaces/HsvTests.cs | 39 +++++ .../Colorspaces/HunterLabTests.cs | 43 +++++ .../Colorspaces/LinearRgbTests.cs | 42 +++++ .../ImageSharp.Tests/Colorspaces/LmsTests.cs | 43 +++++ .../Colorspaces/YCbCrTests.cs | 42 +++++ 29 files changed, 594 insertions(+), 244 deletions(-) create mode 100644 tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/CmykTests.cs delete mode 100644 tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/HslTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/HsvTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/LmsTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 844387b3e1..9e331152c3 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -21,19 +21,19 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). /// public readonly float L; /// /// Gets the a color component. - /// A value ranging from -100 to 100. Negative is green, positive magenta. + /// A value usually ranging from -100 to 100. Negative is green, positive magenta. /// public readonly float A; /// /// Gets the b color component. - /// A value ranging from -100 to 100. Negative is blue, positive is yellow + /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow /// public readonly float B; @@ -64,11 +64,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(InliningOptions.ShortMethod)] public CieLab(float l, float a, float b, CieXyz whitePoint) + : this(new Vector3(l, a, b), whitePoint) { - this.L = l; - this.A = a; - this.B = b; - this.WhitePoint = whitePoint; } /// @@ -91,6 +88,7 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieLab(Vector3 vector, CieXyz whitePoint) : this() { + // Not clamping as documentation about this space seems to indicate "usual" ranges this.L = vector.X; this.A = vector.Y; this.B = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index 47eb53e770..b5ca8a9a0f 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -13,6 +13,9 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct CieLch : IEquatable { + private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Max = new Vector3(100, 200, 360); + /// /// D50 standard illuminant. /// Used when reference white is not specified explicitly. @@ -27,7 +30,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Gets the a chroma component. - /// A value ranging from 0 to 100. + /// A value ranging from 0 to 200. /// public readonly float C; @@ -64,11 +67,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(InliningOptions.ShortMethod)] public CieLch(float l, float c, float h, CieXyz whitePoint) + : this(new Vector3(l, c, h), whitePoint) { - this.L = l; - this.C = c; - this.H = h; - this.WhitePoint = whitePoint; } /// @@ -90,6 +90,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public CieLch(Vector3 vector, CieXyz whitePoint) { + vector = Vector3.Clamp(vector, Min, Max); this.L = vector.X; this.C = vector.Y; this.H = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index a92cad2a3d..8ddad9d328 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -9,10 +9,13 @@ namespace SixLabors.ImageSharp.ColorSpaces { /// /// Represents the CIE L*C*h°, cylindrical form of the CIE L*u*v* 1976 color. - /// + /// /// public readonly struct CieLchuv : IEquatable { + private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Max = new Vector3(100, 200, 360); + /// /// D50 standard illuminant. /// Used when reference white is not specified explicitly. @@ -27,7 +30,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Gets the a chroma component. - /// A value ranging from 0 to 100. + /// A value ranging from 0 to 200. /// public readonly float C; @@ -64,11 +67,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(InliningOptions.ShortMethod)] public CieLchuv(float l, float c, float h, CieXyz whitePoint) + : this(new Vector3(l, c, h), whitePoint) { - this.L = l; - this.C = c; - this.H = h; - this.WhitePoint = whitePoint; } /// @@ -91,6 +91,7 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieLchuv(Vector3 vector, CieXyz whitePoint) : this() { + vector = Vector3.Clamp(vector, Min, Max); this.L = vector.X; this.C = vector.Y; this.H = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index c8639c8162..211732446c 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -15,6 +15,9 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct CieLuv : IEquatable { + private static readonly Vector3 Min = new Vector3(0, -100, -100); + private static readonly Vector3 Max = new Vector3(100, 100, 100); + /// /// D65 standard illuminant. /// Used when reference white is not specified explicitly. @@ -66,11 +69,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The reference white point. [MethodImpl(InliningOptions.ShortMethod)] public CieLuv(float l, float u, float v, CieXyz whitePoint) + : this(new Vector3(l, u, v), whitePoint) { - this.L = l; - this.U = u; - this.V = v; - this.WhitePoint = whitePoint; } /// @@ -92,6 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public CieLuv(Vector3 vector, CieXyz whitePoint) { + vector = Vector3.Clamp(vector, Min, Max); this.L = vector.X; this.U = vector.Y; this.V = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index 8995d3eeba..e57f565b15 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -41,10 +41,6 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieXyz(float x, float y, float z) : this(new Vector3(x, y, z)) { - // Not clamping as documentation about this space seems to indicate "usual" ranges - this.X = x; - this.Y = y; - this.Z = z; } /// diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index 78153eced8..1d64e19951 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -12,6 +12,9 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct Cmyk : IEquatable { + private static readonly Vector4 Min = Vector4.Zero; + private static readonly Vector4 Max = Vector4.One; + /// /// Gets the cyan color component. /// A value ranging between 0 and 1. @@ -56,7 +59,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public Cmyk(Vector4 vector) { - vector = Vector4.Clamp(vector, Vector4.Zero, Vector4.One); + vector = Vector4.Clamp(vector, Min, Max); this.C = vector.X; this.M = vector.Y; this.Y = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index 2197b8504d..acc735bc53 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -12,10 +12,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct Hsl : IEquatable { - /// - /// Max range used for clamping. - /// - private static readonly Vector3 VectorMax = new Vector3(360, 1, 1); + private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Max = new Vector3(360, 1, 1); /// /// Gets the hue component. @@ -54,7 +52,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public Hsl(Vector3 vector) { - vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + vector = Vector3.Clamp(vector, Min, Max); this.H = vector.X; this.S = vector.Y; this.L = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index b10444aff4..caabe9b4b6 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -12,10 +12,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct Hsv : IEquatable { - /// - /// Max range used for clamping. - /// - private static readonly Vector3 VectorMax = new Vector3(360, 1, 1); + private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Max = new Vector3(360, 1, 1); /// /// Gets the hue component. @@ -54,7 +52,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public Hsv(Vector3 vector) { - vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + vector = Vector3.Clamp(vector, Min, Max); this.H = vector.X; this.S = vector.Y; this.V = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index 8771081d5b..23bca423f6 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -13,6 +13,9 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct HunterLab : IEquatable { + private static readonly Vector3 Min = new Vector3(0, -100, -100); + private static readonly Vector3 Max = new Vector3(100, 100, 100); + /// /// D50 standard illuminant. /// Used when reference white is not specified explicitly. @@ -87,7 +90,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public HunterLab(Vector3 vector, CieXyz whitePoint) { - // TODO: Clamp? + vector = Vector3.Clamp(vector, Min, Max); this.L = vector.X; this.A = vector.Y; this.B = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index 14ff919c19..63a5acace1 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -13,6 +13,9 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct LinearRgb : IEquatable { + private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Max = Vector3.One; + /// /// The default LinearRgb working space. /// @@ -85,7 +88,7 @@ namespace SixLabors.ImageSharp.ColorSpaces public LinearRgb(Vector3 vector, RgbWorkingSpace workingSpace) { // Clamp to 0-1 range. - vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + vector = Vector3.Clamp(vector, Min, Max); this.R = vector.X; this.G = vector.Y; this.B = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 2ad7c5a10a..e2b88a24b4 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -40,10 +40,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// S represents the responsivity at short wavelengths. [MethodImpl(InliningOptions.ShortMethod)] public Lms(float l, float m, float s) + : this(new Vector3(l, m, s)) { - this.L = l; - this.M = m; - this.S = s; } /// diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 39fe534535..5a02936993 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -14,6 +14,9 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct Rgb : IEquatable { + private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Max = Vector3.One; + /// /// The default rgb working space /// @@ -63,12 +66,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The rgb working space. [MethodImpl(InliningOptions.ShortMethod)] public Rgb(float r, float g, float b, RgbWorkingSpace workingSpace) + : this(new Vector3(r, g, b), workingSpace) { - // Clamp to 0-1 range. - this.R = r.Clamp(0, 1F); - this.G = g.Clamp(0, 1F); - this.B = b.Clamp(0, 1F); - this.WorkingSpace = workingSpace; } /// @@ -89,8 +88,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public Rgb(Vector3 vector, RgbWorkingSpace workingSpace) { - // Clamp to 0-1 range. - vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); + vector = Vector3.Clamp(vector, Min, Max); this.R = vector.X; this.G = vector.Y; this.B = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index 6b94f4a4a8..7bc59ee767 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -14,10 +14,8 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct YCbCr : IEquatable { - /// - /// Vector which is used in clamping to the max value. - /// - private static readonly Vector3 VectorMax = new Vector3(255F); + private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Max = new Vector3(255); /// /// Gets the Y luminance component. @@ -56,7 +54,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public YCbCr(Vector3 vector) { - vector = Vector3.Clamp(vector, Vector3.Zero, VectorMax); + vector = Vector3.Clamp(vector, Min, Max); this.Y = vector.X; this.Cb = vector.Y; this.Cr = vector.Z; diff --git a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs index 1b0f8ad095..3c8570a2a4 100644 --- a/src/ImageSharp/Common/Extensions/ComparableExtensions.cs +++ b/src/ImageSharp/Common/Extensions/ComparableExtensions.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp /// /// The representing the clamped value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static byte Clamp(this byte value, byte min, byte max) { // Order is important here as someone might set min to higher than max. @@ -46,7 +46,7 @@ namespace SixLabors.ImageSharp /// /// The representing the clamped value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static uint Clamp(this uint value, uint min, uint max) { if (value >= max) @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp /// /// The representing the clamped value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static int Clamp(this int value, int min, int max) { if (value >= max) @@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp /// /// The representing the clamped value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float Clamp(this float value, float min, float max) { if (value >= max) @@ -121,7 +121,7 @@ namespace SixLabors.ImageSharp /// /// The representing the clamped value. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static double Clamp(this double value, double min, double max) { if (value >= max) @@ -136,27 +136,5 @@ namespace SixLabors.ImageSharp return value; } - - /// - /// Converts an to a first restricting the value between the - /// minimum and maximum allowable ranges. - /// - /// The this method extends. - /// The - public static byte ToByte(this float value) - { - return (byte)value.Clamp(0, 255); - } - - /// - /// Converts an to a first restricting the value between the - /// minimum and maximum allowable ranges. - /// - /// The this method extends. - /// The - public static byte ToByte(this double value) - { - return (byte)value.Clamp(0, 255); - } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs new file mode 100644 index 0000000000..a7469243f7 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs @@ -0,0 +1,43 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class CieLabTests + { + [Fact] + public void CieLabConstructorAssignsFields() + { + const float l = 75F; + const float a = -64F; + const float b = 87F; + var cieLab = new CieLab(l, a, b); + + Assert.Equal(l, cieLab.L); + Assert.Equal(a, cieLab.A); + Assert.Equal(b, cieLab.B); + } + + [Fact] + public void CieLabEquality() + { + var x = default(CieLab); + var y = new CieLab(Vector3.One); + + Assert.True(default(CieLab) == default(CieLab)); + Assert.True(default(CieLab) != new CieLab(1, 0, 1)); + Assert.False(default(CieLab) == new CieLab(1, 0, 1)); + Assert.Equal(default(CieLab), default(CieLab)); + Assert.Equal(new CieLab(1, 0, 1), new CieLab(1, 0, 1)); + Assert.Equal(new CieLab(Vector3.One), new CieLab(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs new file mode 100644 index 0000000000..fe4bf17d39 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class CieLchTests + { + [Fact] + public void CieLchConstructorAssignsFields() + { + const float l = 75F; + const float c = 64F; + const float h = 287F; + var cieLch = new CieLch(l, c, h); + + Assert.Equal(l, cieLch.L); + Assert.Equal(c, cieLch.C); + Assert.Equal(h, cieLch.H); + } + + [Fact] + public void CieLchEquality() + { + var x = default(CieLch); + var y = new CieLch(Vector3.One); + Assert.Equal(default(CieLch), default(CieLch)); + Assert.Equal(new CieLch(1, 0, 1), new CieLch(1, 0, 1)); + Assert.Equal(new CieLch(Vector3.One), new CieLch(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs new file mode 100644 index 0000000000..10e1bedf79 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class CieLchuvTests + { + [Fact] + public void CieLchuvConstructorAssignsFields() + { + const float l = 75F; + const float c = 64F; + const float h = 287F; + var cieLchuv = new CieLchuv(l, c, h); + + Assert.Equal(l, cieLchuv.L); + Assert.Equal(c, cieLchuv.C); + Assert.Equal(h, cieLchuv.H); + } + + [Fact] + public void CieLchuvEquality() + { + var x = default(CieLchuv); + var y = new CieLchuv(Vector3.One); + Assert.Equal(default(CieLchuv), default(CieLchuv)); + Assert.Equal(new CieLchuv(1, 0, 1), new CieLchuv(1, 0, 1)); + Assert.Equal(new CieLchuv(Vector3.One), new CieLchuv(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs new file mode 100644 index 0000000000..556becffc3 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class CieLuvTests + { + [Fact] + public void CieLuvConstructorAssignsFields() + { + const float l = 75F; + const float c = -64F; + const float h = 87F; + var cieLuv = new CieLuv(l, c, h); + + Assert.Equal(l, cieLuv.L); + Assert.Equal(c, cieLuv.U); + Assert.Equal(h, cieLuv.V); + } + + [Fact] + public void CieLuvEquality() + { + var x = default(CieLuv); + var y = new CieLuv(Vector3.One); + Assert.Equal(default(CieLuv), default(CieLuv)); + Assert.Equal(new CieLuv(1, 0, 1), new CieLuv(1, 0, 1)); + Assert.Equal(new CieLuv(Vector3.One), new CieLuv(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs new file mode 100644 index 0000000000..df7d8953ff --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class CieXyyTests + { + [Fact] + public void CieXyyConstructorAssignsFields() + { + const float x = 75F; + const float y = 64F; + const float yl = 287F; + var cieXyy = new CieXyy(x, y, yl); + + Assert.Equal(x, cieXyy.X); + Assert.Equal(y, cieXyy.Y); + Assert.Equal(y, cieXyy.Y); + } + + [Fact] + public void CieXyyEquality() + { + var x = default(CieXyy); + var y = new CieXyy(Vector3.One); + Assert.Equal(default(CieXyy), default(CieXyy)); + Assert.Equal(new CieXyy(1, 0, 1), new CieXyy(1, 0, 1)); + Assert.Equal(new CieXyy(Vector3.One), new CieXyy(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs new file mode 100644 index 0000000000..dac7483da4 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class CieXyzTests + { + [Fact] + public void CieXyzConstructorAssignsFields() + { + const float x = 75F; + const float y = 64F; + const float z = 287F; + var cieXyz = new CieXyz(x, y, z); + + Assert.Equal(x, cieXyz.X); + Assert.Equal(y, cieXyz.Y); + Assert.Equal(z, cieXyz.Z); + } + + [Fact] + public void CieXyzEquality() + { + var x = default(CieXyz); + var y = new CieXyz(Vector3.One); + Assert.Equal(default(CieXyz), default(CieXyz)); + Assert.Equal(new CieXyz(1, 0, 1), new CieXyz(1, 0, 1)); + Assert.Equal(new CieXyz(Vector3.One), new CieXyz(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} diff --git a/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs b/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs new file mode 100644 index 0000000000..57ece60c9b --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs @@ -0,0 +1,41 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class CmykTests + { + [Fact] + public void CmykConstructorAssignsFields() + { + const float c = .75F; + const float m = .64F; + const float y = .87F; + const float k = .334F; + var cmyk = new Cmyk(c, m, y, k); + + Assert.Equal(c, cmyk.C); + Assert.Equal(m, cmyk.M); + Assert.Equal(y, cmyk.Y); + Assert.Equal(k, cmyk.K); + } + + [Fact] + public void CmykEquality() + { + var x = default(Cmyk); + var y = new Cmyk(Vector4.One); + Assert.Equal(default(Cmyk), default(Cmyk)); + Assert.Equal(new Cmyk(1, 0, 1, 0), new Cmyk(1, 0, 1, 0)); + Assert.Equal(new Cmyk(Vector4.One), new Cmyk(Vector4.One)); + Assert.False(x.Equals(y)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs b/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs deleted file mode 100644 index df3e0ebfbd..0000000000 --- a/tests/ImageSharp.Tests/Colorspaces/ColorSpaceEqualityTests.cs +++ /dev/null @@ -1,162 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Numerics; -using SixLabors.ImageSharp.ColorSpaces; -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Colorspaces -{ - /// - /// Test implementations of IEquatable and IAlmostEquatable in our colorspaces - /// - public class ColorSpaceEqualityTests - { - [Fact] - public void CieLabEquality() - { - var x = default(CieLab); - var y = new CieLab(Vector3.One); - - Assert.True(default(CieLab) == default(CieLab)); - Assert.True(default(CieLab) != new CieLab(1, 0, 1)); - Assert.False(default(CieLab) == new CieLab(1, 0, 1)); - Assert.Equal(default(CieLab), default(CieLab)); - Assert.Equal(new CieLab(1, 0, 1), new CieLab(1, 0, 1)); - Assert.Equal(new CieLab(Vector3.One), new CieLab(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void CieLchEquality() - { - var x = default(CieLch); - var y = new CieLch(Vector3.One); - Assert.Equal(default(CieLch), default(CieLch)); - Assert.Equal(new CieLch(1, 0, 1), new CieLch(1, 0, 1)); - Assert.Equal(new CieLch(Vector3.One), new CieLch(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void CieLchuvEquality() - { - var x = default(CieLchuv); - var y = new CieLchuv(Vector3.One); - Assert.Equal(default(CieLchuv), default(CieLchuv)); - Assert.Equal(new CieLchuv(1, 0, 1), new CieLchuv(1, 0, 1)); - Assert.Equal(new CieLchuv(Vector3.One), new CieLchuv(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void CieLuvEquality() - { - var x = default(CieLuv); - var y = new CieLuv(Vector3.One); - Assert.Equal(default(CieLuv), default(CieLuv)); - Assert.Equal(new CieLuv(1, 0, 1), new CieLuv(1, 0, 1)); - Assert.Equal(new CieLuv(Vector3.One), new CieLuv(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void CieXyzEquality() - { - var x = default(CieXyz); - var y = new CieXyz(Vector3.One); - Assert.Equal(default(CieXyz), default(CieXyz)); - Assert.Equal(new CieXyz(1, 0, 1), new CieXyz(1, 0, 1)); - Assert.Equal(new CieXyz(Vector3.One), new CieXyz(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void CieXyyEquality() - { - var x = default(CieXyy); - var y = new CieXyy(Vector3.One); - Assert.Equal(default(CieXyy), default(CieXyy)); - Assert.Equal(new CieXyy(1, 0, 1), new CieXyy(1, 0, 1)); - Assert.Equal(new CieXyy(Vector3.One), new CieXyy(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void HslEquality() - { - var x = default(Hsl); - var y = new Hsl(Vector3.One); - Assert.Equal(default(Hsl), default(Hsl)); - Assert.Equal(new Hsl(1, 0, 1), new Hsl(1, 0, 1)); - Assert.Equal(new Hsl(Vector3.One), new Hsl(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void HsvEquality() - { - var x = default(Hsv); - var y = new Hsv(Vector3.One); - Assert.Equal(default(Hsv), default(Hsv)); - Assert.Equal(new Hsv(1, 0, 1), new Hsv(1, 0, 1)); - Assert.Equal(new Hsv(Vector3.One), new Hsv(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void HunterLabEquality() - { - var x = default(HunterLab); - var y = new HunterLab(Vector3.One); - Assert.Equal(default(HunterLab), default(HunterLab)); - Assert.Equal(new HunterLab(1, 0, 1), new HunterLab(1, 0, 1)); - Assert.Equal(new HunterLab(Vector3.One), new HunterLab(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void LmsEquality() - { - var x = default(Lms); - var y = new Lms(Vector3.One); - Assert.Equal(default(Lms), default(Lms)); - Assert.Equal(new Lms(1, 0, 1), new Lms(1, 0, 1)); - Assert.Equal(new Lms(Vector3.One), new Lms(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void LinearRgbEquality() - { - var x = default(LinearRgb); - var y = new LinearRgb(Vector3.One); - Assert.Equal(default(LinearRgb), default(LinearRgb)); - Assert.Equal(new LinearRgb(1, 0, 1), new LinearRgb(1, 0, 1)); - Assert.Equal(new LinearRgb(Vector3.One), new LinearRgb(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void YCbCrEquality() - { - var x = default(YCbCr); - var y = new YCbCr(Vector3.One); - Assert.Equal(default(YCbCr), default(YCbCr)); - Assert.Equal(new YCbCr(1, 0, 1), new YCbCr(1, 0, 1)); - Assert.Equal(new YCbCr(Vector3.One), new YCbCr(Vector3.One)); - Assert.False(x.Equals(y)); - } - - [Fact] - public void CmykEquality() - { - var x = default(Cmyk); - var y = new Cmyk(Vector4.One); - Assert.Equal(default(Cmyk), default(Cmyk)); - Assert.Equal(new Cmyk(1, 0, 1, 0), new Cmyk(1, 0, 1, 0)); - Assert.Equal(new Cmyk(Vector4.One), new Cmyk(Vector4.One)); - Assert.False(x.Equals(y)); - } - } -} diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs index 6b128eff8c..484d302e9a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndLmsConversionTest.cs @@ -70,11 +70,22 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion var converter = new ColorSpaceConverter(); var expected = new Lms(l, m, s); + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + // Act var actual = converter.ToLms(input); + converter.Convert(inputSpan, actualSpan, actualSpan.Length); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/HslTests.cs b/tests/ImageSharp.Tests/Colorspaces/HslTests.cs new file mode 100644 index 0000000000..edd92536b2 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/HslTests.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class HslTests + { + [Fact] + public void HslConstructorAssignsFields() + { + const float h = 275F; + const float s = .64F; + const float l = .87F; + var hsl = new Hsl(h, s, l); + + Assert.Equal(h, hsl.H); + Assert.Equal(s, hsl.S); + Assert.Equal(l, hsl.L); + } + + [Fact] + public void HslEquality() + { + var x = default(Hsl); + var y = new Hsl(Vector3.One); + Assert.Equal(default(Hsl), default(Hsl)); + Assert.Equal(new Hsl(1, 0, 1), new Hsl(1, 0, 1)); + Assert.Equal(new Hsl(Vector3.One), new Hsl(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs b/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs new file mode 100644 index 0000000000..5ccbf5391b --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs @@ -0,0 +1,39 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class HsvTests + { + [Fact] + public void HsvConstructorAssignsFields() + { + const float h = 275F; + const float s = .64F; + const float v = .87F; + var hsv = new Hsv(h, s, v); + + Assert.Equal(h, hsv.H); + Assert.Equal(s, hsv.S); + Assert.Equal(v, hsv.V); + } + + [Fact] + public void HsvEquality() + { + var x = default(Hsv); + var y = new Hsv(Vector3.One); + Assert.Equal(default(Hsv), default(Hsv)); + Assert.Equal(new Hsv(1, 0, 1), new Hsv(1, 0, 1)); + Assert.Equal(new Hsv(Vector3.One), new Hsv(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs b/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs new file mode 100644 index 0000000000..b62fa4088e --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs @@ -0,0 +1,43 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class HunterLabTests + { + [Fact] + public void HunterLabConstructorAssignsFields() + { + const float l = 75F; + const float a = -64F; + const float b = 87F; + var hunterLab = new HunterLab(l, a, b); + + Assert.Equal(l, hunterLab.L); + Assert.Equal(a, hunterLab.A); + Assert.Equal(b, hunterLab.B); + } + + [Fact] + public void HunterLabEquality() + { + var x = default(HunterLab); + var y = new HunterLab(Vector3.One); + + Assert.True(default(HunterLab) == default(HunterLab)); + Assert.True(default(HunterLab) != new HunterLab(1, 0, 1)); + Assert.False(default(HunterLab) == new HunterLab(1, 0, 1)); + Assert.Equal(default(HunterLab), default(HunterLab)); + Assert.Equal(new HunterLab(1, 0, 1), new HunterLab(1, 0, 1)); + Assert.Equal(new HunterLab(Vector3.One), new HunterLab(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs b/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs new file mode 100644 index 0000000000..e352a09205 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs @@ -0,0 +1,42 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class LinearRgbTests + { + [Fact] + public void LinearRgbConstructorAssignsFields() + { + const float r = .75F; + const float g = .64F; + const float b = .87F; + var rgb = new LinearRgb(r, g, b); + + Assert.Equal(r, rgb.R); + Assert.Equal(g, rgb.G); + Assert.Equal(b, rgb.B); + } + + [Fact] + public void LinearRgbEquality() + { + var x = default(LinearRgb); + var y = new LinearRgb(Vector3.One); + + Assert.True(default(LinearRgb) == default(LinearRgb)); + Assert.False(default(LinearRgb) != default(LinearRgb)); + Assert.Equal(default(LinearRgb), default(LinearRgb)); + Assert.Equal(new LinearRgb(1, 0, 1), new LinearRgb(1, 0, 1)); + Assert.Equal(new LinearRgb(Vector3.One), new LinearRgb(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs b/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs new file mode 100644 index 0000000000..dfd07b031d --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs @@ -0,0 +1,43 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class LmsTests + { + [Fact] + public void LmsConstructorAssignsFields() + { + const float l = 75F; + const float m = -64F; + const float s = 87F; + var Lms = new Lms(l, m, s); + + Assert.Equal(l, Lms.L); + Assert.Equal(m, Lms.M); + Assert.Equal(s, Lms.S); + } + + [Fact] + public void LmsEquality() + { + var x = default(Lms); + var y = new Lms(Vector3.One); + + Assert.True(default(Lms) == default(Lms)); + Assert.True(default(Lms) != new Lms(1, 0, 1)); + Assert.False(default(Lms) == new Lms(1, 0, 1)); + Assert.Equal(default(Lms), default(Lms)); + Assert.Equal(new Lms(1, 0, 1), new Lms(1, 0, 1)); + Assert.Equal(new Lms(Vector3.One), new Lms(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs b/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs new file mode 100644 index 0000000000..ebf2ae08d7 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs @@ -0,0 +1,42 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class YCbCrTests + { + [Fact] + public void YCbCrConstructorAssignsFields() + { + const float y = 75F; + const float cb = 64F; + const float cr = 87F; + var yCbCr = new YCbCr(y, cb, cr); + + Assert.Equal(y, yCbCr.Y); + Assert.Equal(cb, yCbCr.Cb); + Assert.Equal(cr, yCbCr.Cr); + } + + [Fact] + public void YCbCrEquality() + { + var x = default(YCbCr); + var y = new YCbCr(Vector3.One); + + Assert.True(default(YCbCr) == default(YCbCr)); + Assert.False(default(YCbCr) != default(YCbCr)); + Assert.Equal(default(YCbCr), default(YCbCr)); + Assert.Equal(new YCbCr(1, 0, 1), new YCbCr(1, 0, 1)); + Assert.Equal(new YCbCr(Vector3.One), new YCbCr(Vector3.One)); + Assert.False(x.Equals(y)); + } + } +} From 4878913e2e1da4f8bb69121aa521ed2490d2b015 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 20:17:06 +0100 Subject: [PATCH 130/185] Upate rgb test format --- tests/ImageSharp.Tests/Colorspaces/RgbTests.cs | 9 ++------- 1 file changed, 2 insertions(+), 7 deletions(-) diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs b/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs index 26352a6147..99fb3cf1af 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs @@ -8,7 +8,6 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Colorspaces { - /// /// Tests the struct. /// @@ -48,9 +47,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces const byte g = 128; const byte b = 255; - var rgb = new Rgb(r / 255F, g / 255F, b / 255F); - - Rgb24 rgb24 = rgb; + Rgb24 rgb24 = new Rgb(r / 255F, g / 255F, b / 255F); Rgb rgb2 = rgb24; Assert.Equal(r, rgb24.R); @@ -69,9 +66,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces const byte g = 128; const byte b = 255; - var rgb = new Rgb(r / 255F, g / 255F, b / 255F); - - Rgba32 rgba32 = rgb; + Rgba32 rgba32 = new Rgb(r / 255F, g / 255F, b / 255F); Rgb rgb2 = rgba32; Assert.Equal(r, rgba32.R); From fce0cf2f0ce6513c356a071cb408ed8b27d034bf Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Oct 2018 20:24:19 +0100 Subject: [PATCH 131/185] Fix accidentally replaced test image --- tests/Images/Input/Png/splash.png | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Images/Input/Png/splash.png b/tests/Images/Input/Png/splash.png index b37ce5b79c..ca4f86bced 100644 --- a/tests/Images/Input/Png/splash.png +++ b/tests/Images/Input/Png/splash.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e9091d56d707eea787687cb77fe526a14d1dd09c2e5f1de27deb71c4b13110fe -size 5081 +oid sha256:f4c13422913f1c1910f8dd607236e79b4a5c7053deb8ce1c8be8372eca7465fb +size 245033 From e71f2b37e931d55f4256db7923704da30a4e0586 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Oct 2018 00:26:14 +0100 Subject: [PATCH 132/185] Added bulk adaptation method plus more tests --- .../ColorSpaceConverter.CieLchuv.cs | 4 +- .../Conversion/ColorSpaceConverter.cs | 13 +-- .../Conversion/IChromaticAdaptation.cs | 19 +++- .../Conversion/VonKriesChromaticAdaptation.cs | 43 ++++++++- src/ImageSharp/ColorSpaces/LinearRgb.cs | 2 +- .../Colorspaces/CieLabTests.cs | 3 + .../Colorspaces/CieLchTests.cs | 5 + .../Colorspaces/CieLchuvTests.cs | 5 + .../Colorspaces/CieLuvTests.cs | 5 + .../CieXyChromaticityCoordinatesTests.cs | 43 +++++++++ .../Colorspaces/CieXyyTests.cs | 5 + .../Colorspaces/CieXyzTests.cs | 5 + .../ImageSharp.Tests/Colorspaces/CmykTests.cs | 5 + .../CieLabAndCieLchConversionTests.cs | 2 +- .../CieLabAndCieLchuvConversionTests.cs | 96 +++++++++++++++++++ .../Conversion/ColorConverterAdaptTest.cs | 55 +++++++++-- .../ImageSharp.Tests/Colorspaces/HslTests.cs | 5 + .../ImageSharp.Tests/Colorspaces/HsvTests.cs | 5 + .../Colorspaces/HunterLabTests.cs | 2 + .../Colorspaces/LinearRgbTests.cs | 2 + .../ImageSharp.Tests/Colorspaces/LmsTests.cs | 2 + .../ImageSharp.Tests/Colorspaces/RgbTests.cs | 2 + .../Colorspaces/StringRepresentationTests.cs | 1 + .../Colorspaces/YCbCrTests.cs | 2 + 24 files changed, 305 insertions(+), 26 deletions(-) create mode 100644 tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 3d77b0076a..8d20ec0a60 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -159,9 +159,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The public CieLchuv ToCieLchuv(in CieXyz color) { - var labColor = this.ToCieLab(color); + var luvColor = this.ToCieLuv(color); - return this.ToCieLchuv(labColor); + return this.ToCieLchuv(luvColor); } /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index 8fd6ca449e..bcbd64c77a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -12,11 +12,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public partial class ColorSpaceConverter { // Options. - private Matrix4x4 lmsAdaptationMatrix; - private CieXyz whitePoint; - private CieXyz targetLuvWhitePoint; - private CieXyz targetLabWhitePoint; - private CieXyz targetHunterLabWhitePoint; + private static readonly ColorSpaceConverterOptions DefaultOptions = new ColorSpaceConverterOptions(); + private readonly Matrix4x4 lmsAdaptationMatrix; + private readonly CieXyz whitePoint; + private readonly CieXyz targetLuvWhitePoint; + private readonly CieXyz targetLabWhitePoint; + private readonly CieXyz targetHunterLabWhitePoint; private readonly RgbWorkingSpace targetRgbWorkingSpace; private readonly IChromaticAdaptation chromaticAdaptation; private readonly bool performChromaticAdaptation; @@ -30,7 +31,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// Initializes a new instance of the class. /// public ColorSpaceConverter() - : this(new ColorSpaceConverterOptions()) + : this(DefaultOptions) { } diff --git a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs index e84b8bf255..1b14c6413e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/IChromaticAdaptation.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; + namespace SixLabors.ImageSharp.ColorSpaces.Conversion { /// @@ -14,10 +16,21 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// Performs a linear transformation of a source color in to the destination color. /// /// Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates). - /// The source color. + /// The source color. /// The source white point. - /// The target white point. + /// The destination white point. /// The - CieXyz Transform(in CieXyz sourceColor, in CieXyz sourceWhitePoint, in CieXyz targetWhitePoint); + CieXyz Transform(in CieXyz source, in CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint); + + /// + /// Performs a bulk linear transformation of a source color in to the destination color. + /// + /// Doesn't crop the resulting color space coordinates (e. g. allows negative values for XYZ coordinates). + /// The span to the source colors. + /// The span to the destination colors. + /// The source white point. + /// The destination white point. + /// The number of colors to convert. + void Transform(Span source, Span destination, CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint, int count); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs index bc840f7467..9b200b8736 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/VonKriesChromaticAdaptation.cs @@ -1,7 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces.Conversion @@ -44,21 +47,51 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion internal VonKriesChromaticAdaptation(CieXyzAndLmsConverter converter) => this.converter = converter; /// - public CieXyz Transform(in CieXyz sourceColor, in CieXyz sourceWhitePoint, in CieXyz targetWhitePoint) + public CieXyz Transform(in CieXyz source, in CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint) { - if (sourceWhitePoint.Equals(targetWhitePoint)) + if (sourceWhitePoint.Equals(destinationWhitePoint)) { - return sourceColor; + return source; } - Lms sourceColorLms = this.converter.Convert(sourceColor); + Lms sourceColorLms = this.converter.Convert(source); Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint); - Lms targetWhitePointLms = this.converter.Convert(targetWhitePoint); + Lms targetWhitePointLms = this.converter.Convert(destinationWhitePoint); Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3(); var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3())); return this.converter.Convert(targetColorLms); } + + /// + public void Transform(Span source, Span destination, CieXyz sourceWhitePoint, in CieXyz destinationWhitePoint, int count) + { + Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); + + if (sourceWhitePoint.Equals(destinationWhitePoint)) + { + source.CopyTo(destination.Slice(0, count)); + return; + } + + ref CieXyz sourceRef = ref MemoryMarshal.GetReference(source); + ref CieXyz destRef = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < count; i++) + { + ref CieXyz sp = ref Unsafe.Add(ref sourceRef, i); + ref CieXyz dp = ref Unsafe.Add(ref destRef, i); + + Lms sourceColorLms = this.converter.Convert(sp); + Lms sourceWhitePointLms = this.converter.Convert(sourceWhitePoint); + Lms targetWhitePointLms = this.converter.Convert(destinationWhitePoint); + + Vector3 vector = targetWhitePointLms.ToVector3() / sourceWhitePointLms.ToVector3(); + var targetColorLms = new Lms(Vector3.Multiply(vector, sourceColorLms.ToVector3())); + + dp = this.converter.Convert(targetColorLms); + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index 63a5acace1..9ecef0a31e 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The blue component ranging between 0 and 1. [MethodImpl(InliningOptions.ShortMethod)] public LinearRgb(float r, float g, float b) - : this(new Vector3(r, g, b)) + : this(r, g, b, DefaultWorkingSpace) { } diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs index a7469243f7..dbc07b916e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLabTests.cs @@ -38,6 +38,9 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces Assert.Equal(new CieLab(1, 0, 1), new CieLab(1, 0, 1)); Assert.Equal(new CieLab(Vector3.One), new CieLab(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(default(CieLab) == new CieLab(1, 0, 1)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs index fe4bf17d39..90c2c22446 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLchTests.cs @@ -30,10 +30,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { var x = default(CieLch); var y = new CieLch(Vector3.One); + + Assert.True(default(CieLch) == default(CieLch)); + Assert.False(default(CieLch) != default(CieLch)); Assert.Equal(default(CieLch), default(CieLch)); Assert.Equal(new CieLch(1, 0, 1), new CieLch(1, 0, 1)); Assert.Equal(new CieLch(Vector3.One), new CieLch(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs index 10e1bedf79..a6a5fa32ad 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLchuvTests.cs @@ -30,10 +30,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { var x = default(CieLchuv); var y = new CieLchuv(Vector3.One); + + Assert.True(default(CieLchuv) == default(CieLchuv)); + Assert.False(default(CieLchuv) != default(CieLchuv)); Assert.Equal(default(CieLchuv), default(CieLchuv)); Assert.Equal(new CieLchuv(1, 0, 1), new CieLchuv(1, 0, 1)); Assert.Equal(new CieLchuv(Vector3.One), new CieLchuv(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs index 556becffc3..dbf64cb1d0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieLuvTests.cs @@ -30,10 +30,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { var x = default(CieLuv); var y = new CieLuv(Vector3.One); + + Assert.True(default(CieLuv) == default(CieLuv)); + Assert.False(default(CieLuv) != default(CieLuv)); Assert.Equal(default(CieLuv), default(CieLuv)); Assert.Equal(new CieLuv(1, 0, 1), new CieLuv(1, 0, 1)); Assert.Equal(new CieLuv(Vector3.One), new CieLuv(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs new file mode 100644 index 0000000000..42ace9dbed --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyChromaticityCoordinatesTests.cs @@ -0,0 +1,43 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using SixLabors.ImageSharp.ColorSpaces; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces +{ + /// + /// Tests the struct. + /// + public class CieXyChromaticityCoordinatesTests + { + [Fact] + public void CieXyChromaticityCoordinatesConstructorAssignsFields() + { + const float x = .75F; + const float y = .64F; + var coordinates = new CieXyChromaticityCoordinates(x, y); + + Assert.Equal(x, coordinates.X); + Assert.Equal(y, coordinates.Y); + } + + [Fact] + public void CieXyChromaticityCoordinatesEquality() + { + var x = default(CieXyChromaticityCoordinates); + var y = new CieXyChromaticityCoordinates(1, 1); + + Assert.True(default(CieXyChromaticityCoordinates) == default(CieXyChromaticityCoordinates)); + Assert.True(default(CieXyChromaticityCoordinates) != new CieXyChromaticityCoordinates(1, 0)); + Assert.False(default(CieXyChromaticityCoordinates) == new CieXyChromaticityCoordinates(1, 0)); + Assert.Equal(default(CieXyChromaticityCoordinates), default(CieXyChromaticityCoordinates)); + Assert.Equal(new CieXyChromaticityCoordinates(1, 0), new CieXyChromaticityCoordinates(1, 0)); + Assert.Equal(new CieXyChromaticityCoordinates(1, 1), new CieXyChromaticityCoordinates(1, 1)); + Assert.False(x.Equals(y)); + Assert.False(default(CieXyChromaticityCoordinates) == new CieXyChromaticityCoordinates(1, 0)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs index df7d8953ff..88196034bf 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyyTests.cs @@ -30,10 +30,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { var x = default(CieXyy); var y = new CieXyy(Vector3.One); + + Assert.True(default(CieXyy) == default(CieXyy)); + Assert.False(default(CieXyy) != default(CieXyy)); Assert.Equal(default(CieXyy), default(CieXyy)); Assert.Equal(new CieXyy(1, 0, 1), new CieXyy(1, 0, 1)); Assert.Equal(new CieXyy(Vector3.One), new CieXyy(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs b/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs index dac7483da4..3c77f132e3 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CieXyzTests.cs @@ -30,10 +30,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { var x = default(CieXyz); var y = new CieXyz(Vector3.One); + + Assert.True(default(CieXyz) == default(CieXyz)); + Assert.False(default(CieXyz) != default(CieXyz)); Assert.Equal(default(CieXyz), default(CieXyz)); Assert.Equal(new CieXyz(1, 0, 1), new CieXyz(1, 0, 1)); Assert.Equal(new CieXyz(Vector3.One), new CieXyz(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs b/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs index 57ece60c9b..dbf3fe6d8a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/CmykTests.cs @@ -32,10 +32,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { var x = default(Cmyk); var y = new Cmyk(Vector4.One); + + Assert.True(default(Cmyk) == default(Cmyk)); + Assert.False(default(Cmyk) != default(Cmyk)); Assert.Equal(default(Cmyk), default(Cmyk)); Assert.Equal(new Cmyk(1, 0, 1, 0), new Cmyk(1, 0, 1, 0)); Assert.Equal(new Cmyk(Vector4.One), new Cmyk(Vector4.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs index d3d7598251..eb9a50d185 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchConversionTests.cs @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion [InlineData(10, -20, 30, 10, 36.0555, 123.6901)] [InlineData(10, 20, -30, 10, 36.0555, 303.6901)] [InlineData(10, -20, -30, 10, 36.0555, 236.3099)] - public void Convert_Lab_to_LCHab(float l, float a, float b, float l2, float c, float h) + public void Convert_Lab_to_Lch(float l, float a, float b, float l2, float c, float h) { // Arrange var input = new CieLab(l, a, b); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs new file mode 100644 index 0000000000..58b2e5bdb3 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs @@ -0,0 +1,96 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + /// + /// Test data generated using: + /// + /// + public class CieLabAndCieLchuvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(54.2917, 106.8391, 40.8526, 54.9205055, 30.7944126, 93.17662)] + [InlineData(100, 0, 0, 100, 0, 0)] + [InlineData(100, 50, 180, 99.74778, -35.5287476, -4.24233675)] + [InlineData(10, 36.0555, 56.3099, 10.2056971, 7.886916, 17.498457)] + [InlineData(10, 36.0555, 123.6901, 9.953703, -35.1176033, 16.8696461)] + [InlineData(10, 36.0555, 303.6901, 9.805839, 55.69225, -36.6074753)] + [InlineData(10, 36.0555, 236.3099, 8.86916, -34.4068336, -42.2136269)] + public void Convert_Lchuv_to_Lab(float l, float c, float h, float l2, float a, float b) + { + // Arrange + var input = new CieLchuv(l, c, h); + var expected = new CieLab(l2, a, b); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(54.9205055, 30.7944126, 93.17662, 54.9205055, 103.269287, 35.46892)] + [InlineData(100, 0, 0, 100, 29.5789261, 60.1635857)] + [InlineData(99.74778, -35.5287476, -4.24233675, 99.74778, 48.8177834, 139.54837)] + [InlineData(10.2056971, 7.886916, 17.498457, 10.205699, 17.00984, 42.9908066)] + [InlineData(9.953703, -35.1176033, 16.8696461, 9.953705, 25.3788586, 141.070892)] + [InlineData(9.805839, 55.69225, -36.6074753, 9.80584049, 35.3214073, 314.4875)] + [InlineData(8.86916, -34.4068336, -42.2136269, 8.869162, 32.1432457, 227.960419)] + + public void Convert_Lab_to_Lchuv(float l, float a, float b, float l2, float c, float h) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new CieLchuv(l2, c, h); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + var actual = Converter.ToCieLchuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs index af9b8c5b33..8c1d930ff8 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(22, 33, 1, 22.269869, 32.841164, 1.633926)] - public void Adapt_Lab_D50_To_D65(float l1, float a1, float b1, float l2, float a2, float b2) + public void Adapt_Lab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) { // Arrange var input = new CieLab(l1, a1, b1, Illuminants.D65); @@ -97,7 +97,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion [Theory] [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(0.5, 0.5, 0.5, 0.507233, 0.500000, 0.378943)] - public void Adapt_CieXyz_D65_To_D50_XyzScaling(float x1, float y1, float z1, float x2, float y2, float z2) + public void Adapt_Xyz_D65_To_D50_XyzScaling(float x1, float y1, float z1, float x2, float y2, float z2) { // Arrange var input = new CieXyz(x1, y1, z1); @@ -119,22 +119,61 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion [Theory] [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(0.5, 0.5, 0.5, 0.507233, 0.500000, 0.378943)] - public void Adapt_Xyz_D65_To_D50_XyzScaling(float x1, float y1, float z1, float x2, float y2, float z2) + [InlineData(22, 33, 1, 22.1090755, 32.2102661, 1.153463)] + public void Adapt_HunterLab_D65_To_D50(float l1, float a1, float b1, float l2, float a2, float b2) { // Arrange - var input = new CieXyz(x1, y1, z1); - var expected = new CieXyz(x2, y2, z2); + var input = new HunterLab(l1, a1, b1, Illuminants.D65); + var expected = new HunterLab(l2, a2, b2); + var options = new ColorSpaceConverterOptions { TargetLabWhitePoint = Illuminants.D50 }; + var converter = new ColorSpaceConverter(options); + + // Action + HunterLab actual = converter.Adapt(input); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(22, 33, 1, 22, 33, 0.9999999)] + public void Adapt_CieLchuv_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) + { + // Arrange + var input = new CieLchuv(l1, c1, h1, Illuminants.D65); + var expected = new CieLchuv(l2, c2, h2); var options = new ColorSpaceConverterOptions { ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), - WhitePoint = Illuminants.D50 + TargetLabWhitePoint = Illuminants.D50 }; + var converter = new ColorSpaceConverter(options); + // Action + CieLchuv actual = converter.Adapt(input); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + } + + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(22, 33, 1, 22, 33, 0.9999999)] + public void Adapt_CieLch_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) + { + // Arrange + var input = new CieLch(l1, c1, h1, Illuminants.D65); + var expected = new CieLch(l2, c2, h2); + var options = new ColorSpaceConverterOptions + { + ChromaticAdaptation = new VonKriesChromaticAdaptation(LmsAdaptationMatrix.XyzScaling), + TargetLabWhitePoint = Illuminants.D50 + }; var converter = new ColorSpaceConverter(options); // Action - CieXyz actual = converter.Adapt(input, Illuminants.D65); + CieLch actual = converter.Adapt(input); // Assert Assert.Equal(expected, actual, ColorSpaceComparer); diff --git a/tests/ImageSharp.Tests/Colorspaces/HslTests.cs b/tests/ImageSharp.Tests/Colorspaces/HslTests.cs index edd92536b2..60cfa9761a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HslTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/HslTests.cs @@ -30,10 +30,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { var x = default(Hsl); var y = new Hsl(Vector3.One); + + Assert.True(default(Hsl) == default(Hsl)); + Assert.False(default(Hsl) != default(Hsl)); Assert.Equal(default(Hsl), default(Hsl)); Assert.Equal(new Hsl(1, 0, 1), new Hsl(1, 0, 1)); Assert.Equal(new Hsl(Vector3.One), new Hsl(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs b/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs index 5ccbf5391b..d1d1d15c8a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/HsvTests.cs @@ -30,10 +30,15 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { var x = default(Hsv); var y = new Hsv(Vector3.One); + + Assert.True(default(Hsv) == default(Hsv)); + Assert.False(default(Hsv) != default(Hsv)); Assert.Equal(default(Hsv), default(Hsv)); Assert.Equal(new Hsv(1, 0, 1), new Hsv(1, 0, 1)); Assert.Equal(new Hsv(Vector3.One), new Hsv(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs b/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs index b62fa4088e..95261e1d98 100644 --- a/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/HunterLabTests.cs @@ -38,6 +38,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces Assert.Equal(new HunterLab(1, 0, 1), new HunterLab(1, 0, 1)); Assert.Equal(new HunterLab(Vector3.One), new HunterLab(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs b/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs index e352a09205..ef42e68bcc 100644 --- a/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/LinearRgbTests.cs @@ -37,6 +37,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces Assert.Equal(new LinearRgb(1, 0, 1), new LinearRgb(1, 0, 1)); Assert.Equal(new LinearRgb(Vector3.One), new LinearRgb(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs b/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs index dfd07b031d..1b0939dc5c 100644 --- a/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/LmsTests.cs @@ -38,6 +38,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces Assert.Equal(new Lms(1, 0, 1), new Lms(1, 0, 1)); Assert.Equal(new Lms(Vector3.One), new Lms(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs b/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs index 99fb3cf1af..7987fbe9f2 100644 --- a/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/RgbTests.cs @@ -38,6 +38,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces Assert.Equal(new Rgb(1, 0, 1), new Rgb(1, 0, 1)); Assert.Equal(new Rgb(Vector3.One), new Rgb(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } [Fact] diff --git a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs b/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs index 44b02f1657..5249b709b1 100644 --- a/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/StringRepresentationTests.cs @@ -42,6 +42,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces { new Hsl(one), "Hsl(1, 1, 1)" }, { new Hsv(one), "Hsv(1, 1, 1)" }, { new YCbCr(one), "YCbCr(1, 1, 1)" }, + { new CieXyChromaticityCoordinates(1, 1), "CieXyChromaticityCoordinates(1, 1)"}, { new CieLab(random), "CieLab(42.4, 94.5, 83.4)" }, { new CieLch(random), "CieLch(42.4, 94.5, 83.4)" }, diff --git a/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs b/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs index ebf2ae08d7..f3e6f88f49 100644 --- a/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/YCbCrTests.cs @@ -37,6 +37,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces Assert.Equal(new YCbCr(1, 0, 1), new YCbCr(1, 0, 1)); Assert.Equal(new YCbCr(Vector3.One), new YCbCr(Vector3.One)); Assert.False(x.Equals(y)); + Assert.False(x.Equals((object)y)); + Assert.False(x.GetHashCode().Equals(y.GetHashCode())); } } } From b8914f002bd1c6b527416f444517e707d0e32147 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 3 Oct 2018 02:12:09 +0200 Subject: [PATCH 133/185] source should be ReadOnlySpan for all bulk-conversion methods + increase tolerance because of failing test case --- .../Conversion/ColorSpaceConverter.CieLab.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.CieLch.cs | 26 +++++++++---------- .../ColorSpaceConverter.CieLchuv.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.CieLuv.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.CieXyy.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.CieXyz.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.Cmyk.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.Hsl.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.Hsv.cs | 26 +++++++++---------- .../ColorSpaceConverter.HunterLab.cs | 26 +++++++++---------- .../ColorSpaceConverter.LinearRgb.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.Lms.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.Rgb.cs | 26 +++++++++---------- .../Conversion/ColorSpaceConverter.YCbCr.cs | 24 ++++++++--------- src/ImageSharp/Common/Helpers/Guard.cs | 22 ++++++++++++++++ .../CieLabAndCieLchuvConversionTests.cs | 3 +-- 16 files changed, 204 insertions(+), 183 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs index e79f51211c..3ce14cdea4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLab.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -172,7 +172,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -204,7 +204,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -237,7 +237,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -302,7 +302,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -335,7 +335,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -368,7 +368,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -401,7 +401,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -434,7 +434,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs index 601a874d51..3c9e6658cd 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLch.cs @@ -38,7 +38,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -202,7 +202,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -235,7 +235,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -268,7 +268,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -301,7 +301,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -334,7 +334,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -367,7 +367,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -400,7 +400,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -433,7 +433,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs index 8d20ec0a60..01de794885 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLchuv.cs @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -137,7 +137,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -203,7 +203,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -236,7 +236,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -269,7 +269,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -302,7 +302,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -335,7 +335,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -368,7 +368,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -401,7 +401,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -433,7 +433,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index b58c838106..55b96c3539 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -131,7 +131,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -166,7 +166,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -198,7 +198,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -262,7 +262,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -294,7 +294,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -326,7 +326,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -358,7 +358,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -390,7 +390,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -422,7 +422,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs index b50f699afb..b77f48325f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyy.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -193,7 +193,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -226,7 +226,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -259,7 +259,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -292,7 +292,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -325,7 +325,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -358,7 +358,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -391,7 +391,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -424,7 +424,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 2d70c83d67..5d110552a4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -41,7 +41,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -76,7 +76,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -146,7 +146,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -212,7 +212,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -246,7 +246,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -280,7 +280,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -315,7 +315,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -351,7 +351,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -383,7 +383,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -416,7 +416,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -450,7 +450,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs index bc6c9a949c..6f8fe61469 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Cmyk.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -198,7 +198,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -264,7 +264,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -330,7 +330,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -363,7 +363,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -391,7 +391,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -424,7 +424,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs index d88c3a2f23..106e8956f1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsl.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -198,7 +198,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -264,7 +264,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -330,7 +330,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -363,7 +363,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -391,7 +391,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -424,7 +424,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs index 01ade4375d..8b4e29215c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Hsv.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -198,7 +198,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -264,7 +264,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -330,7 +330,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -363,7 +363,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -391,7 +391,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -424,7 +424,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs index ddc225d1de..b3286a9cc4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.HunterLab.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -192,7 +192,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -224,7 +224,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -256,7 +256,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -288,7 +288,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -320,7 +320,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -352,7 +352,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -384,7 +384,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -416,7 +416,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs index f230c0e6fd..98943c034a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.LinearRgb.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -259,7 +259,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -291,7 +291,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -355,7 +355,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -387,7 +387,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -419,7 +419,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs index 91162cb49b..ffd0f88d11 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Lms.cs @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -61,7 +61,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -93,7 +93,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -125,7 +125,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -157,7 +157,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -185,7 +185,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -217,7 +217,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -249,7 +249,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -281,7 +281,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -313,7 +313,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -345,7 +345,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -377,7 +377,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -409,7 +409,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs index 31ec3dd401..cd40c966b1 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.Rgb.cs @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -96,7 +96,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -160,7 +160,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -195,7 +195,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -227,7 +227,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -259,7 +259,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -291,7 +291,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -323,7 +323,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -355,7 +355,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -387,7 +387,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -422,7 +422,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs index 993108c40e..38e6d5fae0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.YCbCr.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -66,7 +66,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -132,7 +132,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -165,7 +165,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -198,7 +198,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -231,7 +231,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -264,7 +264,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -297,7 +297,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -330,7 +330,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -363,7 +363,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); @@ -391,7 +391,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// The span to the source colors /// The span to the destination colors /// The number of colors to convert. - public void Convert(Span source, Span destination, int count) + public void Convert(ReadOnlySpan source, Span destination, int count) { Guard.SpansMustBeSizedAtLeast(source, nameof(source), destination, nameof(destination), count); diff --git a/src/ImageSharp/Common/Helpers/Guard.cs b/src/ImageSharp/Common/Helpers/Guard.cs index 038d5c35c8..34ba544726 100644 --- a/src/ImageSharp/Common/Helpers/Guard.cs +++ b/src/ImageSharp/Common/Helpers/Guard.cs @@ -264,5 +264,27 @@ namespace SixLabors.ImageSharp MustBeSizedAtLeast(source, minLength, sourceParamName); MustBeSizedAtLeast(dest, minLength, destParamName); } + + /// + /// Verifies that the given 'source' and 'dest' spans are at least of 'minLength' size. + /// Throwing an if the condition is not met. + /// + /// The source element type + /// The destination element type + /// The source span + /// The source parameter name + /// The destination span + /// The destination parameter name + /// The minimum length + public static void SpansMustBeSizedAtLeast( + ReadOnlySpan source, + string sourceParamName, + Span dest, + string destParamName, + int minLength) + { + MustBeSizedAtLeast(source, minLength, sourceParamName); + MustBeSizedAtLeast(dest, minLength, destParamName); + } } } diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs index 58b2e5bdb3..9c15401b51 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion /// public class CieLabAndCieLchuvConversionTests { - private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); /// @@ -68,7 +68,6 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion [InlineData(9.953703, -35.1176033, 16.8696461, 9.953705, 25.3788586, 141.070892)] [InlineData(9.805839, 55.69225, -36.6074753, 9.80584049, 35.3214073, 314.4875)] [InlineData(8.86916, -34.4068336, -42.2136269, 8.869162, 32.1432457, 227.960419)] - public void Convert_Lab_to_Lchuv(float l, float a, float b, float l2, float c, float h) { // Arrange From d7fa37179328d11ed955d7fdb0d7995bb7dbeb2f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Oct 2018 09:34:26 +0100 Subject: [PATCH 134/185] Normalise inlining, remove flaky test. --- .../Implementation/CIeLchToCieLabConverter.cs | 2 +- .../Implementation/CieLabToCieLchConverter.cs | 4 +-- .../Implementation/CieLabToCieXyzConverter.cs | 2 +- .../CieLchuvToCieLuvConverter.cs | 2 +- .../CieLuvToCieLchuvConverter.cs | 4 +-- .../Implementation/CieLuvToCieXyzConverter.cs | 16 ++++-------- .../CieXyzAndCieXyyConverter.cs | 4 +-- .../CieXyzAndHunterLabConverterBase.cs | 4 +-- .../Implementation/CieXyzAndLmsConverter.cs | 6 ++--- .../Implementation/CieXyzToCieLabConverter.cs | 9 ++----- .../Implementation/CieXyzToCieLuvConverter.cs | 18 +++---------- .../CieXyzToHunterLabConverter.cs | 9 ++----- .../CieXyzToLinearRgbConverter.cs | 4 +-- .../Implementation/CmykAndRgbConverter.cs | 4 +-- .../Implementation/GammaCompanding.cs | 26 +++++-------------- .../Implementation/HslAndRgbConverter.cs | 12 ++++----- .../Implementation/HsvAndRgbConverter.cs | 4 +-- .../HunterLabToCieXyzConverter.cs | 2 +- .../Conversion/Implementation/LCompanding.cs | 8 +++--- .../LinearRgbAndCieXyzConverterBase.cs | 1 - .../LinearRgbToCieXyzConverter.cs | 2 ++ .../Implementation/LinearRgbToRgbConverter.cs | 3 ++- .../Implementation/LmsAdaptationMatrix.cs | 1 - .../RGBPrimariesChromaticityCoordinates.cs | 3 +-- .../Implementation/Rec2020Companding.cs | 12 +++------ .../Implementation/Rec709Companding.cs | 12 +++------ .../Implementation/RgbToLinearRgbConverter.cs | 3 ++- .../Implementation/RgbWorkingSpace.cs | 3 +-- .../Implementation/YCbCrAndRgbConverter.cs | 4 +-- .../Common/Helpers/InliningOptions.cs | 4 +-- .../Conversion/ColorConverterAdaptTest.cs | 1 - 31 files changed, 67 insertions(+), 122 deletions(-) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs index 7a71a1cc44..dd352db809 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLab Convert(in CieLch input) { // Conversion algorithm described here: diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs index 150f198882..81196604e5 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLch Convert(in CieLab input) { // Conversion algorithm described here: @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float hDegrees = MathFExtensions.RadianToDegree(hRadians); // Wrap the angle round at 360. - hDegrees = hDegrees % 360; + hDegrees %= 360; // Make sure it's not negative. while (hDegrees < 0) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs index 707300eda2..dfbbc8f0c7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieXyz Convert(in CieLab input) { // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Lab_to_XYZ.html diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs index c3e85ba735..4f5a20bec7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLuv Convert(in CieLchuv input) { // Conversion algorithm described here: diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs index b8e5d6f903..297c18c5c3 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLchuv Convert(in CieLuv input) { // Conversion algorithm described here: @@ -27,7 +27,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float hDegrees = MathFExtensions.RadianToDegree(hRadians); // Wrap the angle round at 360. - hDegrees = hDegrees % 360; + hDegrees %= 360; // Make sure it's not negative. while (hDegrees < 0) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs index ecd26fdf6d..33f3ec3d3e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation @@ -16,7 +15,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyz Convert(in CieLuv input) { // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_Luv_to_XYZ.html @@ -31,7 +29,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation float a = ((52 * l / (u + (13 * l * u0))) - 1) / 3; float b = -5 * y; - float c = -0.3333333F; + const float c = -0.3333333F; float d = y * ((39 * l / (v + (13 * l * v0))) - 5); float x = (d - b) / (a - c); @@ -60,21 +58,17 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The whitepoint /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static float ComputeU0(in CieXyz input) - { - return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); - } + => (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); /// /// Calculates the red-green chromacity based on the given whitepoint. /// /// The whitepoint /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static float ComputeV0(in CieXyz input) - { - return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); - } + => (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs index 32c1fe4c8e..f33d1ddcc9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieXyy Convert(in CieXyz input) { float x = input.X / (input.X + input.Y + input.Z); @@ -36,7 +36,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieXyz Convert(in CieXyy input) { if (MathF.Abs(input.Y) < Constants.Epsilon) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndHunterLabConverterBase.cs index 238a343d05..1cd511e819 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndHunterLabConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndHunterLabConverterBase.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The whitepoint /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float ComputeKa(CieXyz whitePoint) { if (whitePoint.Equals(Illuminants.C)) @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The whitepoint /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static float ComputeKb(CieXyz whitePoint) { if (whitePoint == Illuminants.C) diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs index ed7ccff28c..f860652b18 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs @@ -23,7 +23,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Initializes a new instance of the class. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzAndLmsConverter() : this(DefaultTransformationMatrix) { @@ -36,7 +35,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Definition of the cone response domain (see ), /// if not set will be used. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzAndLmsConverter(Matrix4x4 transformationMatrix) { this.transformationMatrix = transformationMatrix; @@ -48,7 +46,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Lms Convert(in CieXyz input) { var vector = Vector3.Transform(input.ToVector3(), this.transformationMatrix); @@ -61,7 +59,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieXyz Convert(in Lms input) { var vector = Vector3.Transform(input.ToVector3(), this.inverseTransformationMatrix); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs index 54d3e0fecf..c155087ff5 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs @@ -14,7 +14,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Initializes a new instance of the class. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzToCieLabConverter() : this(CieLab.DefaultWhitePoint) { @@ -24,11 +23,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Initializes a new instance of the class. /// /// The target reference lab white point - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public CieXyzToCieLabConverter(CieXyz labWhitePoint) - { - this.LabWhitePoint = labWhitePoint; - } + public CieXyzToCieLabConverter(CieXyz labWhitePoint) => this.LabWhitePoint = labWhitePoint; /// /// Gets the target reference whitepoint. When not set, is used. @@ -40,7 +35,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieLab Convert(in CieXyz input) { // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Lab.html diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs index 79128e7299..7f2bb0cf6a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs @@ -14,7 +14,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Initializes a new instance of the class. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzToCieLuvConverter() : this(CieLuv.DefaultWhitePoint) { @@ -24,11 +23,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Initializes a new instance of the class. /// /// The target reference luv white point - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public CieXyzToCieLuvConverter(CieXyz luvWhitePoint) - { - this.LuvWhitePoint = luvWhitePoint; - } + public CieXyzToCieLuvConverter(CieXyz luvWhitePoint) => this.LuvWhitePoint = luvWhitePoint; /// /// Gets the target reference whitepoint. When not set, is used. @@ -40,7 +35,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieLuv Convert(in CieXyz input) { // Conversion algorithm described here: http://www.brucelindbloom.com/index.html?Eqn_XYZ_to_Luv.html @@ -80,19 +74,15 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] private static float ComputeUp(in CieXyz input) - { - return (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); - } + => (4 * input.X) / (input.X + (15 * input.Y) + (3 * input.Z)); /// /// Calculates the red-green chromacity based on the given whitepoint. /// /// The whitepoint /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static float ComputeVp(in CieXyz input) - { - return (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); - } + => (9 * input.Y) / (input.X + (15 * input.Y) + (3 * input.Z)); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs index 31d4332e40..c27c61608d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs @@ -14,7 +14,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Initializes a new instance of the class. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzToHunterLabConverter() : this(HunterLab.DefaultWhitePoint) { @@ -24,11 +23,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Initializes a new instance of the class. /// /// The hunter Lab white point. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public CieXyzToHunterLabConverter(CieXyz labWhitePoint) - { - this.HunterLabWhitePoint = labWhitePoint; - } + public CieXyzToHunterLabConverter(CieXyz labWhitePoint) => this.HunterLabWhitePoint = labWhitePoint; /// /// Gets the target reference white. When not set, is used. @@ -40,7 +35,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public HunterLab Convert(in CieXyz input) { // Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs index cb3e7d20c8..9ccea497b4 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs @@ -16,7 +16,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Initializes a new instance of the class. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzToLinearRgbConverter() : this(Rgb.DefaultWorkingSpace) { @@ -26,7 +25,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Initializes a new instance of the class. /// /// The target working space. - [MethodImpl(MethodImplOptions.AggressiveInlining)] public CieXyzToLinearRgbConverter(RgbWorkingSpace workingSpace) { this.TargetWorkingSpace = workingSpace; @@ -43,7 +41,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public LinearRgb Convert(in CieXyz input) { Matrix4x4.Invert(this.conversionMatrix, out Matrix4x4 inverted); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs index b81c70a1bd..29fd32905b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb Convert(in Cmyk input) { Vector3 rgb = (Vector3.One - new Vector3(input.C, input.M, input.Y)) * (Vector3.One - new Vector3(input.K)); @@ -29,7 +29,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Cmyk Convert(in Rgb input) { // To CMY diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs index 45ad0d3196..92751e4201 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs @@ -19,33 +19,19 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Initializes a new instance of the class. /// /// The gamma value. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public GammaCompanding(float gamma) - { - this.Gamma = gamma; - } + public GammaCompanding(float gamma) => this.Gamma = gamma; /// /// Gets the gamma value /// - public float Gamma - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get; - } + public float Gamma { get; } /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Expand(float channel) - { - return MathF.Pow(channel, this.Gamma); - } + [MethodImpl(InliningOptions.ShortMethod)] + public float Expand(float channel) => MathF.Pow(channel, this.Gamma); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Compress(float channel) - { - return MathF.Pow(channel, 1 / this.Gamma); - } + [MethodImpl(InliningOptions.ShortMethod)] + public float Compress(float channel) => MathF.Pow(channel, 1 / this.Gamma); } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs index eca114c7b0..761313b7e0 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb Convert(in Hsl input) { float rangedH = input.H / 360F; @@ -52,7 +52,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Hsl Convert(in Rgb input) { float r = input.R; @@ -111,7 +111,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static float GetColorComponent(float first, float second, float third) { third = MoveIntoRange(third); @@ -142,16 +142,16 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static float MoveIntoRange(float value) { if (value < 0F) { - value += 1F; + value++; } else if (value > 1F) { - value -= 1F; + value--; } return value; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs index 79bfe73311..20ada7e7dd 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb Convert(in Hsv input) { float s = input.S; @@ -84,7 +84,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Hsv Convert(in Rgb input) { float r = input.R; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs index 7d71c48a08..783d29a557 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs @@ -16,7 +16,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public CieXyz Convert(in HunterLab input) { // Conversion algorithm described here: http://en.wikipedia.org/wiki/Lab_color_space#Hunter_Lab diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs index 6e87769d79..085230fbde 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs @@ -17,14 +17,12 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public sealed class LCompanding : ICompanding { /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public float Expand(float channel) - { - return channel <= 0.08 ? 100 * channel / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F); - } + => channel <= 0.08 ? 100 * channel / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public float Compress(float channel) { return channel <= CieConstants.Epsilon diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs index 18b3df0d05..bdf451cd3c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs @@ -18,7 +18,6 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace) { DebugGuard.NotNull(workingSpace, nameof(workingSpace)); - RgbPrimariesChromaticityCoordinates chromaticity = workingSpace.ChromaticityCoordinates; float xr = chromaticity.R.X; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs index 1108f682f5..21a96071af 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Numerics; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { @@ -40,6 +41,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result + [MethodImpl(InliningOptions.ShortMethod)] public CieXyz Convert(in LinearRgb input) { DebugGuard.IsTrue(input.WorkingSpace.Equals(this.SourceWorkingSpace), nameof(input.WorkingSpace), "Input and source working spaces must be equal."); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs index 1418f96d71..ad3ed88ef7 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Numerics; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { @@ -15,6 +15,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result + [MethodImpl(InliningOptions.ShortMethod)] public Rgb Convert(in LinearRgb input) { var vector = input.ToVector3(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs index 452cafe794..37e4b1a1a6 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LmsAdaptationMatrix.cs @@ -3,7 +3,6 @@ using System.Numerics; -// ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs index 758f5f7dcc..14c4d6d777 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs @@ -92,8 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { int hashCode = this.R.GetHashCode(); hashCode = (hashCode * 397) ^ this.G.GetHashCode(); - hashCode = (hashCode * 397) ^ this.B.GetHashCode(); - return hashCode; + return (hashCode * 397) ^ this.B.GetHashCode(); } } } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs index 8fea53c8b9..d541c3d972 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs @@ -16,17 +16,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public sealed class Rec2020Companding : ICompanding { /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public float Expand(float channel) - { - return channel < 0.08145F ? channel / 4.5F : MathF.Pow((channel + 0.0993F) / 1.0993F, 2.222222F); - } + => channel < 0.08145F ? channel / 4.5F : MathF.Pow((channel + 0.0993F) / 1.0993F, 2.222222F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public float Compress(float channel) - { - return channel < 0.0181F ? 4500F * channel : (1.0993F * channel) - 0.0993F; - } + => channel < 0.0181F ? 4500F * channel : (1.0993F * channel) - 0.0993F; } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs index c5ed1076db..77f51e4955 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs @@ -15,17 +15,13 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public sealed class Rec709Companding : ICompanding { /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public float Expand(float channel) - { - return channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, 2.222222F); - } + => channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, 2.222222F); /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public float Compress(float channel) - { - return channel < 0.018F ? 4500F * channel : (1.099F * channel) - 0.099F; - } + => channel < 0.018F ? 4500F * channel : (1.099F * channel) - 0.099F; } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs index d3399d1d59..20e2d240a2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System.Numerics; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { @@ -15,6 +15,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result + [MethodImpl(InliningOptions.ShortMethod)] public LinearRgb Convert(in Rgb input) { var vector = input.ToVector3(); diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs index 2b8672f27a..7e1135b2ed 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs @@ -84,8 +84,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { int hash = this.WhitePoint.GetHashCode(); hash = HashHelpers.Combine(hash, this.ChromaticityCoordinates.GetHashCode()); - hash = HashHelpers.Combine(hash, this.Companding?.GetHashCode() ?? 0); - return hash; + return HashHelpers.Combine(hash, this.Companding?.GetHashCode() ?? 0); } } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs index a2484ec0b4..4ac3ad3cf9 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Rgb Convert(in YCbCr input) { float y = input.Y; @@ -39,7 +39,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The input color instance. /// The converted result - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public YCbCr Convert(in Rgb input) { Vector3 rgb = input.ToVector3() * MaxBytes; diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index e1d51da8d4..ad85c4fc81 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -8,12 +8,12 @@ using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp { /// - /// Global inlining options. Helps temporarily disable inling for better profiler output. + /// Global inlining options. Helps temporarily disable inlining for better profiler output. /// internal static class InliningOptions { #if PROFILING - public const MethodImplOptions ShortMethod = 0; + public const MethodImplOptions ShortMethod = MethodImplOptions.NoInlining; #else public const MethodImplOptions ShortMethod = MethodImplOptions.AggressiveInlining; #endif diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs index 8c1d930ff8..326777f3c6 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ColorConverterAdaptTest.cs @@ -158,7 +158,6 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } [Theory] - [InlineData(0, 0, 0, 0, 0, 0)] [InlineData(22, 33, 1, 22, 33, 0.9999999)] public void Adapt_CieLch_D65_To_D50_XyzScaling(float l1, float c1, float h1, float l2, float c2, float h2) { From 9ebebeac0fdcc3587b5be07101c2a9ecd3994be7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Oct 2018 17:37:50 +0100 Subject: [PATCH 135/185] Add CieLab tests --- src/ImageSharp/ColorSpaces/CieLab.cs | 2 +- src/ImageSharp/ColorSpaces/CieLuv.cs | 5 +- src/ImageSharp/ColorSpaces/CieXyy.cs | 4 +- src/ImageSharp/ColorSpaces/CieXyz.cs | 2 +- .../Conversion/ColorSpaceConverter.CieLuv.cs | 2 +- src/ImageSharp/ColorSpaces/HunterLab.cs | 11 +- src/ImageSharp/ColorSpaces/Lms.cs | 2 +- .../ApproximateColorspaceComparer.cs | 103 +++++------------- .../CieLabAndCieLchuvConversionTests.cs | 16 +-- .../CieLabAndCieLuvConversionTests.cs | 83 ++++++++++++++ .../CieLabAndCieXyyConversionTests.cs | 79 ++++++++++++++ .../CieLabAndCmykConversionTests.cs | 79 ++++++++++++++ .../Conversion/CieLabAndHslConversionTests.cs | 79 ++++++++++++++ .../Conversion/CieLabAndHsvConversionTests.cs | 79 ++++++++++++++ .../CieLabAndHunterLabConversionTests.cs | 79 ++++++++++++++ .../CieLabAndLinearRgbConversionTests.cs | 79 ++++++++++++++ .../Conversion/CieLabAndLmsConversionTests.cs | 79 ++++++++++++++ .../Conversion/CieLabAndRgbConversionTests.cs | 79 ++++++++++++++ .../CieLabAndYCbCrConversionTests.cs | 79 ++++++++++++++ .../CieLuvAndCieLchuvConversionTests.cs | 2 +- .../VonKriesChromaticAdaptationTests.cs | 41 +++++++ 21 files changed, 878 insertions(+), 106 deletions(-) create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 9e331152c3..230ea0bdc3 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -88,7 +88,7 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieLab(Vector3 vector, CieXyz whitePoint) : this() { - // Not clamping as documentation about this space seems to indicate "usual" ranges + // Not clamping as documentation about this space only indicates "usual" ranges this.L = vector.X; this.A = vector.Y; this.B = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index 211732446c..9aac268e1c 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -15,9 +15,6 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct CieLuv : IEquatable { - private static readonly Vector3 Min = new Vector3(0, -100, -100); - private static readonly Vector3 Max = new Vector3(100, 100, 100); - /// /// D65 standard illuminant. /// Used when reference white is not specified explicitly. @@ -92,7 +89,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public CieLuv(Vector3 vector, CieXyz whitePoint) { - vector = Vector3.Clamp(vector, Min, Max); + // Not clamping as documentation about this space only indicates "usual" ranges this.L = vector.X; this.U = vector.Y; this.V = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index e8e129df90..44696a9dba 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public CieXyy(float x, float y, float yl) { - // Not clamping as documentation about this space seems to indicate "usual" ranges + // Not clamping as documentation about this space only indicates "usual" ranges this.X = x; this.Y = y; this.Yl = yl; @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieXyy(Vector3 vector) : this() { - // Not clamping as documentation about this space seems to indicate "usual" ranges + // Not clamping as documentation about this space only indicates "usual" ranges this.X = vector.X; this.Y = vector.Y; this.Yl = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index e57f565b15..4fed9f4eda 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -50,7 +50,7 @@ namespace SixLabors.ImageSharp.ColorSpaces public CieXyz(Vector3 vector) : this() { - // Not clamping as documentation about this space seems to indicate "usual" ranges + // Not clamping as documentation about this space only indicates "usual" ranges this.X = vector.X; this.Y = vector.Y; this.Z = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs index 55b96c3539..0b469e065f 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieLuv.cs @@ -154,7 +154,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion public CieLuv ToCieLuv(in CieXyz color) { // Adaptation - CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLabWhitePoint); + CieXyz adapted = this.Adapt(color, this.whitePoint, this.targetLuvWhitePoint); // Conversion return this.cieXyzToCieLuvConverter.Convert(adapted); diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index 23bca423f6..ed30fa93b2 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -13,9 +13,6 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct HunterLab : IEquatable { - private static readonly Vector3 Min = new Vector3(0, -100, -100); - private static readonly Vector3 Max = new Vector3(100, 100, 100); - /// /// D50 standard illuminant. /// Used when reference white is not specified explicitly. @@ -24,19 +21,19 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Gets the lightness dimension. - /// A value ranging between 0 (black), 100 (diffuse white) or higher (specular white). + /// A value usually ranging between 0 (black), 100 (diffuse white) or higher (specular white). /// public readonly float L; /// /// Gets the a color component. - /// A value ranging from -100 to 100. Negative is green, positive magenta. + /// A value usually ranging from -100 to 100. Negative is green, positive magenta. /// public readonly float A; /// /// Gets the b color component. - /// A value ranging from -100 to 100. Negative is blue, positive is yellow + /// A value usually ranging from -100 to 100. Negative is blue, positive is yellow /// public readonly float B; @@ -90,7 +87,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public HunterLab(Vector3 vector, CieXyz whitePoint) { - vector = Vector3.Clamp(vector, Min, Max); + // Not clamping as documentation about this space only indicates "usual" ranges this.L = vector.X; this.A = vector.Y; this.B = vector.Z; diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index e2b88a24b4..59a4069b00 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -51,7 +51,7 @@ namespace SixLabors.ImageSharp.ColorSpaces [MethodImpl(InliningOptions.ShortMethod)] public Lms(Vector3 vector) { - // Not clamping as documentation about this space seems to indicate "usual" ranges + // Not clamping as documentation about this space only indicates "usual" ranges this.L = vector.X; this.M = vector.Y; this.S = vector.Z; diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs index 169a907b14..19b8c2272e 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs @@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion /// internal readonly struct ApproximateColorSpaceComparer : IEqualityComparer, + IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer, @@ -34,10 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion /// Initializes a new instance of the class. /// /// The comparison error difference epsilon to use. - public ApproximateColorSpaceComparer(float epsilon = 1F) - { - this.Epsilon = epsilon; - } + public ApproximateColorSpaceComparer(float epsilon = 1F) => this.Epsilon = epsilon; /// public bool Equals(Rgb x, Rgb y) @@ -48,11 +46,19 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(Rgb obj) + public int GetHashCode(Rgb obj) => obj.GetHashCode(); + + /// + public bool Equals(LinearRgb x, LinearRgb y) { - return obj.GetHashCode(); + return this.Equals(x.R, y.R) + && this.Equals(x.G, y.G) + && this.Equals(x.B, y.B); } + /// + public int GetHashCode(LinearRgb obj) => obj.GetHashCode(); + /// public bool Equals(CieLab x, CieLab y) { @@ -62,10 +68,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(CieLab obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(CieLab obj) => obj.GetHashCode(); /// public bool Equals(CieLch x, CieLch y) @@ -76,10 +79,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(CieLch obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(CieLch obj) => obj.GetHashCode(); /// public bool Equals(CieLchuv x, CieLchuv y) @@ -90,10 +90,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(CieLchuv obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(CieLchuv obj) => obj.GetHashCode(); /// public bool Equals(CieLuv x, CieLuv y) @@ -104,10 +101,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(CieLuv obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(CieLuv obj) => obj.GetHashCode(); /// public bool Equals(CieXyz x, CieXyz y) @@ -118,10 +112,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(CieXyz obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(CieXyz obj) => obj.GetHashCode(); /// public bool Equals(CieXyy x, CieXyy y) @@ -132,10 +123,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(CieXyy obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(CieXyy obj) => obj.GetHashCode(); /// public bool Equals(Cmyk x, Cmyk y) @@ -147,10 +135,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(Cmyk obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(Cmyk obj) => obj.GetHashCode(); /// public bool Equals(HunterLab x, HunterLab y) @@ -161,10 +146,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(HunterLab obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(HunterLab obj) => obj.GetHashCode(); /// public bool Equals(Hsl x, Hsl y) @@ -175,10 +157,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(Hsl obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(Hsl obj) => obj.GetHashCode(); /// public bool Equals(Hsv x, Hsv y) @@ -189,10 +168,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(Hsv obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(Hsv obj) => obj.GetHashCode(); /// public bool Equals(Lms x, Lms y) @@ -203,10 +179,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(Lms obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(Lms obj) => obj.GetHashCode(); /// public bool Equals(YCbCr x, YCbCr y) @@ -217,34 +190,19 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(YCbCr obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(YCbCr obj) => obj.GetHashCode(); /// - public bool Equals(CieXyChromaticityCoordinates x, CieXyChromaticityCoordinates y) - { - return this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y); - } + public bool Equals(CieXyChromaticityCoordinates x, CieXyChromaticityCoordinates y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y); /// - public int GetHashCode(CieXyChromaticityCoordinates obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(CieXyChromaticityCoordinates obj) => obj.GetHashCode(); /// - public bool Equals(RgbPrimariesChromaticityCoordinates x, RgbPrimariesChromaticityCoordinates y) - { - return this.Equals(x.R, y.R) && this.Equals(x.G, y.G) && this.Equals(x.B, y.B); - } + public bool Equals(RgbPrimariesChromaticityCoordinates x, RgbPrimariesChromaticityCoordinates y) => this.Equals(x.R, y.R) && this.Equals(x.G, y.G) && this.Equals(x.B, y.B); /// - public int GetHashCode(RgbPrimariesChromaticityCoordinates obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(RgbPrimariesChromaticityCoordinates obj) => obj.GetHashCode(); /// public bool Equals(RgbWorkingSpace x, RgbWorkingSpace y) @@ -260,10 +218,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } /// - public int GetHashCode(RgbWorkingSpace obj) - { - return obj.GetHashCode(); - } + public int GetHashCode(RgbWorkingSpace obj) => obj.GetHashCode(); private bool Equals(float x, float y) { diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs index 9c15401b51..7fb5770ddb 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLchuvConversionTests.cs @@ -25,13 +25,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(54.2917, 106.8391, 40.8526, 54.9205055, 30.7944126, 93.17662)] - [InlineData(100, 0, 0, 100, 0, 0)] - [InlineData(100, 50, 180, 99.74778, -35.5287476, -4.24233675)] - [InlineData(10, 36.0555, 56.3099, 10.2056971, 7.886916, 17.498457)] - [InlineData(10, 36.0555, 123.6901, 9.953703, -35.1176033, 16.8696461)] - [InlineData(10, 36.0555, 303.6901, 9.805839, 55.69225, -36.6074753)] - [InlineData(10, 36.0555, 236.3099, 8.86916, -34.4068336, -42.2136269)] + [InlineData(30.66194, 200, 352.7564, 31.95653, 116.8745, 2.388602)] public void Convert_Lchuv_to_Lab(float l, float c, float h, float l2, float a, float b) { // Arrange @@ -61,13 +55,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion /// [Theory] [InlineData(0, 0, 0, 0, 0, 0)] - [InlineData(54.9205055, 30.7944126, 93.17662, 54.9205055, 103.269287, 35.46892)] - [InlineData(100, 0, 0, 100, 29.5789261, 60.1635857)] - [InlineData(99.74778, -35.5287476, -4.24233675, 99.74778, 48.8177834, 139.54837)] - [InlineData(10.2056971, 7.886916, 17.498457, 10.205699, 17.00984, 42.9908066)] - [InlineData(9.953703, -35.1176033, 16.8696461, 9.953705, 25.3788586, 141.070892)] - [InlineData(9.805839, 55.69225, -36.6074753, 9.80584049, 35.3214073, 314.4875)] - [InlineData(8.86916, -34.4068336, -42.2136269, 8.869162, 32.1432457, 227.960419)] + [InlineData(36.0555, 303.6901, 10.01514, 30.66194, 200, 352.7564)] public void Convert_Lab_to_Lchuv(float l, float a, float b, float l2, float c, float h) { // Arrange diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..14a1c6fd37 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieLuvConversionTests.cs @@ -0,0 +1,83 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + /// + /// Test data generated using: + /// + /// + public class CieLabAndCieLuvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(10, 36.0555, 303.6901, 10.0151367, -23.9644356, 17.0226)] + public void Convert_CieLuv_to_CieLab(float l, float u, float v, float l2, float a, float b) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new CieLab(l2, a, b); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(10.0151367, -23.9644356, 17.0226, 10.0000038, -12.830183, 15.1829338)] + public void Convert_CieLab_to_CieLuv(float l, float a, float b, float l2, float u, float v) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new CieLuv(l2, u, v); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..9a42a9d47d --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCieXyyConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLabAndCieXyyConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.8644734, 0.06098868, 0.06509002, 36.05552, 275.6228, 10.01517)] + public void Convert_CieXyy_to_CieLab(float x, float y, float yl, float l, float a, float b) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new CieLab(l, a, b); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 303.6901, 10.01514, 0.8644734, 0.06098868, 0.06509002)] + public void Convert_CieLab_to_CieXyy(float l, float a, float b, float x, float y, float yl) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs new file mode 100644 index 0000000000..944fab574e --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndCmykConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLabAndCmykConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 1, 0, 0, 0)] + [InlineData(0, 1, 0.6156551, 5.960464E-08, 55.063, 82.54871, 23.16506)] + public void Convert_Cmyk_to_CieLab(float c, float m, float y, float k, float l, float a, float b) + { + // Arrange + var input = new Cmyk(c, m, y, k); + var expected = new CieLab(l, a, b); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0, 1)] + [InlineData(36.0555, 303.6901, 10.01514, 0, 1, 0.6156551, 5.960464E-08)] + public void Convert_CieLab_to_Cmyk(float l, float a, float b, float c, float m, float y, float k) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs new file mode 100644 index 0000000000..836be1bf27 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHslConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLabAndHslConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(336.9393, 1, 0.5, 55.063, 82.54868, 23.16508)] + public void Convert_Hsl_to_CieLab(float h, float s, float ll, float l, float a, float b) + { + // Arrange + var input = new Hsl(h, s, ll); + var expected = new CieLab(l, a, b); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 303.6901, 10.01514, 336.9393, 1, 0.5)] + public void Convert_CieLab_to_Hsl(float l, float a, float b, float h, float s, float ll) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new Hsl(h, s, ll); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + var actual = Converter.ToHsl(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs new file mode 100644 index 0000000000..fb1982bfc8 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHsvConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLabAndHsvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(336.9393, 1, 0.9999999, 55.063, 82.54871, 23.16504)] + public void Convert_Hsv_to_CieLab(float h, float s, float v, float l, float a, float b) + { + // Arrange + var input = new Hsv(h, s, v); + var expected = new CieLab(l, a, b); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 303.6901, 10.01514, 336.9393, 1, 0.9999999)] + public void Convert_CieLab_to_Hsv(float l, float a, float b, float h, float s, float v) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new Hsv(h, s, v); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + var actual = Converter.ToHsv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..7e3c4251bf --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndHunterLabConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLabAndHunterLabConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(27.51646, 556.9392, -0.03974226, 36.05554, 275.6227, 10.01519)] + public void Convert_HunterLab_to_CieLab(float l2, float a2, float b2, float l, float a, float b) + { + // Arrange + var input = new HunterLab(l2, a2, b2); + var expected = new CieLab(l, a, b); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 303.6901, 10.01514, 27.51646, 556.9392, -0.03974226)] + public void Convert_CieLab_to_HunterLab(float l, float a, float b, float l2, float a2, float b2) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new HunterLab(l2, a2, b2); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + var actual = Converter.ToHunterLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs new file mode 100644 index 0000000000..a43f0095d7 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLinearRgbConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLabAndLinearRgbConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(1, 0, 0.1221596, 55.063, 82.54871, 23.16505)] + public void Convert_LinearRgb_to_CieLab(float r, float g, float b2, float l, float a, float b) + { + // Arrange + var input = new LinearRgb(r, g, b2); + var expected = new CieLab(l, a, b); + + Span inputSpan = new LinearRgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 303.6901, 10.01514, 1, 0, 0.1221596)] + public void Convert_CieLab_to_LinearRgb(float l, float a, float b, float r, float g, float b2) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new LinearRgb(r, g, b2); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new LinearRgb[5]; + + // Act + var actual = Converter.ToLinearRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs new file mode 100644 index 0000000000..62d08263a6 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndLmsConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLabAndLmsConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.8303261, -0.5776886, 0.1133359, 36.05553, 275.6228, 10.01518)] + public void Convert_Lms_to_CieLab(float l2, float m, float s, float l, float a, float b) + { + // Arrange + var input = new Lms(l2, m, s); + var expected = new CieLab(l, a, b); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 303.6901, 10.01514, 0.8303261, -0.5776886, 0.1133359)] + public void Convert_CieLab_to_Lms(float l, float a, float b, float l2, float m, float s) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new Lms(l2, m, s); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + var actual = Converter.ToLms(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs new file mode 100644 index 0000000000..1b30412752 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndRgbConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLabAndRgbConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.9999999, 0, 0.384345, 55.063, 82.54871, 23.16505)] + public void Convert_Rgb_to_CieLab(float r, float g, float b2, float l, float a, float b) + { + // Arrange + var input = new Rgb(r, g, b2); + var expected = new CieLab(l, a, b); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 303.6901, 10.01514, 0.9999999, 0, 0.384345)] + public void Convert_CieLab_to_Rgb(float l, float a, float b, float r, float g, float b2) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new Rgb(r, g, b2); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + var actual = Converter.ToRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..53d33af2b1 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLabAndYCbCrConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLabAndYCbCrConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(87.4179, 133.9763, 247.5308, 55.06287, 82.54838, 23.1697)] + public void Convert_YCbCr_to_CieLab(float y, float cb, float cr, float l, float a, float b) + { + // Arrange + var input = new YCbCr(y, cb, cr); + var expected = new CieLab(l, a, b); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLab[5]; + + // Act + var actual = Converter.ToCieLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(36.0555, 303.6901, 10.01514, 87.4179, 133.9763, 247.5308)] + public void Convert_CieLab_to_YCbCr(float l, float a, float b, float y, float cb, float cr) + { + // Arrange + var input = new CieLab(l, a, b); + var expected = new YCbCr(y, cb, cr); + + Span inputSpan = new CieLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + var actual = Converter.ToYCbCr(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs index be510f95d8..ec599619c0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion /// Test data generated using: /// /// - public class CieLuvAndCieLchuvuvConversionTests + public class CieLuvAndCieLchuvConversionTests { private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs new file mode 100644 index 0000000000..cfd48b694d --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/VonKriesChromaticAdaptationTests.cs @@ -0,0 +1,41 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + public class VonKriesChromaticAdaptationTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); + public static readonly TheoryData WhitePoints = new TheoryData + { + {CieLuv.DefaultWhitePoint, CieLab.DefaultWhitePoint}, + {CieLuv.DefaultWhitePoint, CieLuv.DefaultWhitePoint} + }; + + [Theory] + [MemberData(nameof(WhitePoints))] + public void SingleAndBulkTransformYieldIdenticalResults(CieXyz sourceWhitePoint, CieXyz destinationWhitePoint) + { + var adaptation = new VonKriesChromaticAdaptation(); + var input = new CieXyz(1, 0, 1); + CieXyz expected = adaptation.Transform(input, sourceWhitePoint, destinationWhitePoint); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + adaptation.Transform(inputSpan, actualSpan, sourceWhitePoint, destinationWhitePoint, inputSpan.Length); + + for (int i = 0; i < inputSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} From f1967c33d54b5f0b83141f13a3deec737c9fd5aa Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Oct 2018 19:59:17 +0100 Subject: [PATCH 136/185] CieLuv tests --- src/ImageSharp/ColorSpaces/CieLch.cs | 2 +- src/ImageSharp/ColorSpaces/CieLchuv.cs | 2 +- .../CieLchAndCieXyyConversionTests.cs | 79 ++++++++++++++++++ .../CieLchuvAndCieLchConversionTests.cs | 78 ++++++++++++++++++ ...cs => CieLchuvAndCieLuvConversionTests.cs} | 6 +- .../CieLchuvAndCmykConversionTests.cs | 79 ++++++++++++++++++ .../CieLuvAndCieXyyConversionTests.cs | 80 +++++++++++++++++++ .../Conversion/CieLuvAndHslConversionTests.cs | 80 +++++++++++++++++++ .../Conversion/CieLuvAndHsvConversionTests.cs | 80 +++++++++++++++++++ .../CieLuvAndHunterLabConversionTests.cs | 80 +++++++++++++++++++ .../CieLuvAndLinearRgbConversionTests.cs | 80 +++++++++++++++++++ .../Conversion/CieLuvAndLmsConversionTests.cs | 80 +++++++++++++++++++ .../Conversion/CieLuvAndRgbConversionTests.cs | 80 +++++++++++++++++++ .../CieLuvAndYCbCrConversionTests.cs | 80 +++++++++++++++++++ 14 files changed, 881 insertions(+), 5 deletions(-) create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs rename tests/ImageSharp.Tests/Colorspaces/Conversion/{CieLuvAndCieLchuvConversionTests.cs => CieLchuvAndCieLuvConversionTests.cs} (92%) create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index b5ca8a9a0f..2c8f030e24 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct CieLch : IEquatable { - private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Min = new Vector3(0, -200, 0); private static readonly Vector3 Max = new Vector3(100, 200, 360); /// diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index 8ddad9d328..2aaff48a09 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// public readonly struct CieLchuv : IEquatable { - private static readonly Vector3 Min = Vector3.Zero; + private static readonly Vector3 Min = new Vector3(0, -200, 0); private static readonly Vector3 Max = new Vector3(100, 200, 360); /// diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..18b8a47397 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieXyyConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchAndCieXyyConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 0.6529307, 0.2147411, 0.08447381)] + public void Convert_CieLch_to_CieXyy(float l, float c, float h, float x, float y, float yl) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0.6529307, 0.2147411, 0.08447381, 36.05552, 103.6901, 10.01515)] + public void Convert_CieXyy_to_CieLch(float x, float y, float yl, float l, float c, float h) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new CieLch(l, c, h); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs new file mode 100644 index 0000000000..e7f511bab1 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLchConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchuvAndCieLchConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.73742, 64.79149, 30.1786, 36.0555, 103.6901, 10.01513)] + public void Convert_CieLch_to_CieLchuv(float l2, float c2, float h2, float l, float c, float h) + { + // Arrange + var input = new CieLch(l2, c2, h2); + var expected = new CieLchuv(l, c, h); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + var actual = Converter.ToCieLchuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(36.0555, 103.6901, 10.01514, 36.73742, 64.79149, 30.1786)] + public void Convert_CieLchuv_to_CieLch(float l, float c, float h, float l2, float c2, float h2) + { + // Arrange + var input = new CieLchuv(l, c, h); + var expected = new CieLch(l2, c2, h2); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs similarity index 92% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs rename to tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs index ec599619c0..3bc4fd519b 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieLchuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCieLuvConversionTests.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion /// Test data generated using: /// /// - public class CieLuvAndCieLchuvConversionTests + public class CieLchuvAndCieLuvConversionTests { private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0001F); private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); @@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion [InlineData(10, 36.0555, 123.6901, 10, -20, 30)] [InlineData(10, 36.0555, 303.6901, 10, 20, -30)] [InlineData(10, 36.0555, 236.3099, 10, -20, -30)] - public void Convert_Lchuv_to_Luv(float l, float c, float h, float l2, float u, float v) + public void Convert_CieLchuv_to_CieLuv(float l, float c, float h, float l2, float u, float v) { // Arrange var input = new CieLchuv(l, c, h); @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion [InlineData(10, 20, -30, 10, 36.0555, 303.6901)] [InlineData(10, -20, -30, 10, 36.0555, 236.3099)] [InlineData(37.3511, 24.1720, 16.0684, 37.3511, 29.0255, 33.6141)] - public void Convert_Luv_to_LCHuv(float l, float u, float v, float l2, float c, float h) + public void Convert_CieLuv_to_CieLchuv(float l, float u, float v, float l2, float c, float h) { // Arrange var input = new CieLuv(l, u, v); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs new file mode 100644 index 0000000000..f3940e4d14 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchuvAndCmykConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchuvAndCmykConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 1, 0, 0, 0)] + [InlineData(0, 0.8576171, 0.7693201, 0.3440427, 36.0555, 103.6901, 10.01514)] + public void Convert_Cmyk_to_CieLchuv(float c2, float m, float y, float k, float l, float c, float h) + { + // Arrange + var input = new Cmyk(c2, m, y, k); + var expected = new CieLchuv(l, c, h); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + var actual = Converter.ToCieLchuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0, 1)] + [InlineData(36.0555, 103.6901, 10.01514, 0, 0.8576171, 0.7693201, 0.3440427)] + public void Convert_CieLchuv_to_Cmyk(float l, float c, float h, float c2, float m, float y, float k) + { + // Arrange + var input = new CieLchuv(l, c, h); + var expected = new Cmyk(c2, m, y, k); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..61bfe79634 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndCieXyyConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLuvAndCieXyyConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 0.5646762, 0.2932749, 0.09037033)] + public void Convert_CieLuv_to_CieXyy(float l, float u, float v, float x, float y, float yl) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.5646762, 0.2932749, 0.09037033, 36.0555, 103.6901, 10.01514)] + public void Convert_CieXyy_to_CieLuv(float x, float y, float yl, float l, float u, float v) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new CieLuv(l, u, v); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs new file mode 100644 index 0000000000..7bc430aa37 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHslConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLuvAndHslConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.7115612, 0.3765343)] + public void Convert_CieLuv_to_Hsl(float l, float u, float v, float h, float s, float l2) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new Hsl(h, s, l2); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + var actual = Converter.ToHsl(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(347.3767, 0.7115612, 0.3765343, 36.0555, 93.69012, 10.01514)] + public void Convert_Hsl_to_CieLuv(float h, float s, float l2, float l, float u, float v) + { + // Arrange + var input = new Hsl(h, s, l2); + var expected = new CieLuv(l, u, v); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs new file mode 100644 index 0000000000..23cc5082c4 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHsvConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLuvAndHsvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 347.3767, 0.8314762, 0.6444615)] + public void Convert_CieLuv_to_Hsv(float l, float u, float v, float h, float s, float v2) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new Hsv(h, s, v2); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + var actual = Converter.ToHsv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(347.3767, 0.8314762, 0.6444615, 36.0555, 93.69012, 10.01514)] + public void Convert_Hsv_to_CieLuv(float h, float s, float v2, float l, float u, float v) + { + // Arrange + var input = new Hsv(h, s, v2); + var expected = new CieLuv(l, u, v); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..04699bde46 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndHunterLabConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLuvAndHunterLabConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 30.19531, 46.4312, 11.16259)] + public void Convert_CieLuv_to_HunterLab(float l, float u, float v, float l2, float a, float b) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new HunterLab(l2, a, b); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + var actual = Converter.ToHunterLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(30.19531, 46.4312, 11.16259, 36.0555, 93.6901, 10.01514)] + public void Convert_HunterLab_to_CieLuv(float l2, float a, float b, float l, float u, float v) + { + // Arrange + var input = new HunterLab(l2, a, b); + var expected = new CieLuv(l, u, v); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs new file mode 100644 index 0000000000..98914a6b92 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLinearRgbConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLuvAndLinearRgbConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 0.3729299, 0.01141088, 0.04014909)] + public void Convert_CieLuv_to_LinearRgb(float l, float u, float v, float r, float g, float b) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new LinearRgb(r, g, b); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new LinearRgb[5]; + + // Act + var actual = Converter.ToLinearRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.3729299, 0.01141088, 0.04014909, 36.0555, 93.6901, 10.01511)] + public void Convert_LinearRgb_to_CieLuv(float r, float g, float b, float l, float u, float v) + { + // Arrange + var input = new LinearRgb(r, g, b); + var expected = new CieLuv(l, u, v); + + Span inputSpan = new LinearRgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs new file mode 100644 index 0000000000..306d60b531 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndLmsConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLuvAndLmsConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 0.164352, 0.03267485, 0.0483408)] + public void Convert_CieLuv_to_Lms(float l, float u, float v, float l2, float m, float s) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new Lms(l2, m, s); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + var actual = Converter.ToLms(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.164352, 0.03267485, 0.0483408, 36.0555, 93.69009, 10.01514)] + public void Convert_Lms_to_CieLuv(float l2, float m, float s, float l, float u, float v) + { + // Arrange + var input = new Lms(l2, m, s); + var expected = new CieLuv(l, u, v); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs new file mode 100644 index 0000000000..21cf08dede --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndRgbConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLuvAndRgbConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 93.6901, 10.01514, 0.6444615, 0.1086071, 0.2213444)] + public void Convert_CieLuv_to_Rgb(float l, float u, float v, float r, float g, float b) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new Rgb(r, g, b); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + var actual = Converter.ToRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.6444615, 0.1086071, 0.2213444, 36.0555, 93.69012, 10.01514)] + public void Convert_Rgb_to_CieLuv(float r, float g, float b, float l, float u, float v) + { + // Arrange + var input = new Rgb(r, g, b); + var expected = new CieLuv(l, u, v); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..8c07c38d60 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLuvAndYCbCrConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLuvAndYCbCrConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(36.0555, 93.6901, 10.01514, 71.8283, 119.3174, 193.9839)] + public void Convert_CieLuv_to_YCbCr(float l, float u, float v, float y, float cb, float cr) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new YCbCr(y, cb, cr); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + var actual = Converter.ToYCbCr(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(71.8283, 119.3174, 193.9839, 36.00565, 93.44593, 10.2234)] + public void Convert_YCbCr_to_CieLuv(float y, float cb, float cr, float l, float u, float v) + { + // Arrange + var input = new YCbCr(y, cb, cr); + var expected = new CieLuv(l, u, v); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file From fa7c3a15803a510a36c39400f8e692a70db22ef1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Oct 2018 22:36:57 +0100 Subject: [PATCH 137/185] CieXyy tests --- .../Conversion/CieXyyAndHslConversionTests.cs | 80 +++++++++++++++++++ .../Conversion/CieXyyAndHsvConversionTests.cs | 80 +++++++++++++++++++ .../CieXyyAndHunterLabConversionTests.cs | 80 +++++++++++++++++++ .../CieXyyAndLinearRgbConversionTests.cs | 80 +++++++++++++++++++ .../Conversion/CieXyyAndLmsConversionTests.cs | 80 +++++++++++++++++++ .../Conversion/CieXyyAndRgbConversionTests.cs | 80 +++++++++++++++++++ .../CieXyyAndYCbCrConversionTests.cs | 80 +++++++++++++++++++ 7 files changed, 560 insertions(+) create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs new file mode 100644 index 0000000000..fb415f43ba --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHslConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyyAndHslConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.211263)] + public void Convert_CieXyy_to_Hsl(float x, float y, float yl, float h, float s, float l) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new Hsl(h, s, l); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + var actual = Converter.ToHsl(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.211263, 0.3, 0.6, 0.1067051)] + public void Convert_Hsl_to_CieXyy(float h, float s, float l, float x, float y, float yl) + { + // Arrange + var input = new Hsl(h, s, l); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs new file mode 100644 index 0000000000..3c8aee807a --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHsvConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyyAndHsvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.4225259)] + public void Convert_CieXyy_to_Hsv(float x, float y, float yl, float h, float s, float v) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new Hsv(h, s, v); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + var actual = Converter.ToHsv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.4225259, 0.3, 0.6, 0.1067051)] + public void Convert_Hsv_to_CieXyy(float h, float s, float v, float x, float y, float yl) + { + // Arrange + var input = new Hsv(h, s, v); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..1fcbb75cb2 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndHunterLabConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyyAndHunterLabConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 31.46263, -32.81796, 28.64938)] + public void Convert_CieXyy_to_HunterLab(float x, float y, float yl, float l, float a, float b) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new HunterLab(l, a, b); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + var actual = Converter.ToHunterLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(31.46263, -32.81796, 28.64938, 0.3605552, 0.9369011, 0.1001514)] + public void Convert_HunterLab_to_CieXyy(float l, float a, float b, float x, float y, float yl) + { + // Arrange + var input = new HunterLab(l, a, b); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs new file mode 100644 index 0000000000..8c45378ed4 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLinearRgbConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyyAndLinearRgbConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 0, 0.1492062, 0)] + public void Convert_CieXyy_to_LinearRgb(float x, float y, float yl, float r, float g, float b) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new LinearRgb(r, g, b); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new LinearRgb[5]; + + // Act + var actual = Converter.ToLinearRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0, 0.1492062, 0, 0.3, 0.6, 0.1067051)] + public void Convert_LinearRgb_to_CieXyy(float r, float g, float b, float x, float y, float yl) + { + // Arrange + var input = new LinearRgb(r, g, b); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new LinearRgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs new file mode 100644 index 0000000000..67ec26f6d4 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndLmsConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyyAndLmsConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 0.06631134, 0.1415282, -0.03809926)] + public void Convert_CieXyy_to_Lms(float x, float y, float yl, float l, float m, float s) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new Lms(l, m, s); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + var actual = Converter.ToLms(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.06631134, 0.1415282, -0.03809926, 0.360555, 0.9369009, 0.1001514)] + public void Convert_Lms_to_CieXyy(float l, float m, float s, float x, float y, float yl) + { + // Arrange + var input = new Lms(l, m, s); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs new file mode 100644 index 0000000000..e309e2d555 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndRgbConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyyAndRgbConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 0, 0.4225259, 0)] + public void Convert_CieXyy_to_Rgb(float x, float y, float yl, float r, float g, float b) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new Rgb(r, g, b); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + var actual = Converter.ToRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0, 0.4225259, 0, 0.3, 0.6, 0.1067051)] + public void Convert_Rgb_to_CieXyy(float r, float g, float b, float x, float y, float yl) + { + // Arrange + var input = new Rgb(r, g, b); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..3e33f05192 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyyAndYCbCrConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyyAndYCbCrConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(0.360555, 0.936901, 0.1001514, 63.24579, 92.30826, 82.88884)] + public void Convert_CieXyy_to_YCbCr(float x, float y, float yl, float y2, float cb, float cr) + { + // Arrange + var input = new CieXyy(x, y, yl); + var expected = new YCbCr(y2, cb, cr); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + var actual = Converter.ToYCbCr(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(63.24579, 92.30826, 82.88884, 0.3, 0.6, 0.1072441)] + public void Convert_YCbCr_to_CieXyy(float y2, float cb, float cr, float x, float y, float yl) + { + // Arrange + var input = new YCbCr(y2, cb, cr); + var expected = new CieXyy(x, y, yl); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file From 77f6c1738fbbdfcb3f2273a617cb845d60306399 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 4 Oct 2018 08:27:00 +0100 Subject: [PATCH 138/185] Fix #721 --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 3 ++- .../ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs | 5 +++-- tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/External | 2 +- tests/Images/Input/Jpg/issues/Issue721-InvalidAPP0.jpg | 3 +++ 5 files changed, 10 insertions(+), 4 deletions(-) create mode 100644 tests/Images/Input/Jpg/issues/Issue721-InvalidAPP0.jpg diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 011b6100dc..e3b0b4bdc6 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -510,7 +510,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg /// The remaining bytes in the segment block. private void ProcessApplicationHeaderMarker(int remaining) { - if (remaining < 5) + // We can only decode JFif identifiers. + if (remaining < JFifMarker.Length) { // Skip the application header length this.InputStream.Skip(remaining); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index a14c4735f5..2f041e3ab4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -25,7 +25,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.MultiHuffmanBaseline394, TestImages.Jpeg.Issues.ExifDecodeOutOfRange694, TestImages.Jpeg.Issues.InvalidEOI695, - TestImages.Jpeg.Issues.ExifResizeOutOfRange696 + TestImages.Jpeg.Issues.ExifResizeOutOfRange696, + TestImages.Jpeg.Issues.InvalidAPP0721 }; public static string[] ProgressiveTestJpegs = @@ -54,7 +55,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159 }; - private static readonly Dictionary CustomToleranceValues = + private static readonly Dictionary CustomToleranceValues = new Dictionary { // Baseline: diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index acfad042eb..309fb1d4ab 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -155,6 +155,7 @@ namespace SixLabors.ImageSharp.Tests public const string ExifDecodeOutOfRange694 = "Jpg/issues/Issue694-Decode-Exif-OutOfRange.jpg"; public const string InvalidEOI695 = "Jpg/issues/Issue695-Invalid-EOI.jpg"; public const string ExifResizeOutOfRange696 = "Jpg/issues/Issue696-Resize-Exif-OutOfRange.jpg"; + public const string InvalidAPP0721 = "Jpg/issues/Issue721-InvalidAPP0.jpg"; } public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); diff --git a/tests/Images/External b/tests/Images/External index 7f4d2d64c6..5f3cbd839f 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 7f4d2d64c6b820ca2b6827e6a8540a1013305ccf +Subproject commit 5f3cbd839fbbffae615d294d1dabafdcabc64cf9 diff --git a/tests/Images/Input/Jpg/issues/Issue721-InvalidAPP0.jpg b/tests/Images/Input/Jpg/issues/Issue721-InvalidAPP0.jpg new file mode 100644 index 0000000000..adaea47e55 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/Issue721-InvalidAPP0.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9775b7b975422d48a192d54dce140c1df19a181da9889eb99ee7d4331078b460 +size 1225163 From 6f9875d946aa15d9f1a0a4885337d5ad1383826e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 4 Oct 2018 20:46:08 +0100 Subject: [PATCH 139/185] Decode components in correct order + cleanup + optimizations. --- .../ColorSpaceGenerator.csproj | 1 + .../Jpeg/Components/Decoder/FastACTables.cs | 27 +++++++---------- .../Jpeg/Components/Decoder/HuffmanTable.cs | 3 +- .../Jpeg/Components/Decoder/JpegFrame.cs | 6 ++++ .../Jpeg/Components/Decoder/ScanDecoder.cs | 30 ++++++++----------- .../Formats/Jpeg/JpegDecoderCore.cs | 14 +++++---- .../Formats/Jpg/JpegDecoderTests.Images.cs | 3 ++ tests/ImageSharp.Tests/TestImages.cs | 3 ++ tests/Images/External | 2 +- ...e723-Ordered-Interleaved-Progressive-A.jpg | 3 ++ ...e723-Ordered-Interleaved-Progressive-B.jpg | 3 ++ ...e723-Ordered-Interleaved-Progressive-C.jpg | 3 ++ 12 files changed, 55 insertions(+), 43 deletions(-) create mode 100644 ColorSpaceGenerator/ColorSpaceGenerator.csproj create mode 100644 tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-A.jpg create mode 100644 tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-B.jpg create mode 100644 tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-C.jpg diff --git a/ColorSpaceGenerator/ColorSpaceGenerator.csproj b/ColorSpaceGenerator/ColorSpaceGenerator.csproj new file mode 100644 index 0000000000..7727272f8f --- /dev/null +++ b/ColorSpaceGenerator/ColorSpaceGenerator.csproj @@ -0,0 +1 @@ + diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs index 26bcde8e51..a7ec93eaf7 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs @@ -20,29 +20,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// Initializes a new instance of the class. /// /// The memory allocator used to allocate memory for image processing operations. - public FastACTables(MemoryAllocator memoryAllocator) - { - this.tables = memoryAllocator.Allocate2D(512, 4, AllocationOptions.Clean); - } + public FastACTables(MemoryAllocator memoryAllocator) => this.tables = memoryAllocator.Allocate2D(512, 4, AllocationOptions.Clean); /// /// Gets the representing the table at the index in the collection. /// /// The table index. /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ReadOnlySpan GetTableSpan(int index) - { - return this.tables.GetRowSpan(index); - } + [MethodImpl(InliningOptions.ShortMethod)] + public ReadOnlySpan GetTableSpan(int index) => this.tables.GetRowSpan(index); /// - /// Gets a reference to the first element of the AC table indexed by /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public ref short GetAcTableReference(JpegComponent component) - { - return ref this.tables.GetRowSpan(component.ACHuffmanTableId)[0]; - } + /// Gets a reference to the first element of the AC table indexed by + /// + /// The frame component. + [MethodImpl(InliningOptions.ShortMethod)] + public ref short GetAcTableReference(JpegComponent component) => ref this.tables.GetRowSpan(component.ACHuffmanTableId)[0]; /// /// Builds a lookup table for fast AC entropy scan decoding. @@ -67,7 +60,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder int magbits = rs & 15; int len = huffman.Sizes[fast]; - if (magbits > 0 && len + magbits <= FastBits) + if (magbits != 0 && len + magbits <= FastBits) { // Magnitude code followed by receive_extend code int k = ((i << len) & ((1 << FastBits) - 1)) >> (FastBits - magbits); @@ -80,7 +73,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // if the result is small enough, we can fit it in fastAC table if (k >= -128 && k <= 127) { - fastAC[i] = (short)((k * 256) + (run * 16) + (len + magbits)); + fastAC[i] = (short)((k << 8) + (run << 4) + (len + magbits)); } } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index 0138164ed2..a6bf1bd953 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -64,8 +64,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder byte l = count[i]; for (short j = 0; j < l; j++) { - sizesRef[x] = i; - x++; + sizesRef[x++] = i; } } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs index da089fa44a..36a3dc2d26 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs @@ -45,6 +45,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// public byte[] ComponentIds { get; set; } + /// + /// Gets or sets the order in which to process the components + /// in interleaved mode. + /// + public byte[] ComponentOrder { get; set; } + /// /// Gets or sets the frame component collection /// diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index 8c525335bc..6741ccdac2 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -34,9 +34,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // The restart interval. private readonly int restartInterval; - // The current component index. - private readonly int componentIndex; - // The number of interleaved components. private readonly int componentsLength; @@ -87,7 +84,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// The DC Huffman tables. /// The AC Huffman tables. /// The fast AC decoding tables. - /// The component index within the array. /// The length of the components. Different to the array length. /// The reset interval. /// The spectral selection start. @@ -100,7 +96,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder HuffmanTables dcHuffmanTables, HuffmanTables acHuffmanTables, FastACTables fastACTables, - int componentIndex, int componentsLength, int restartInterval, int spectralStart, @@ -117,7 +112,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder this.components = frame.Components; this.marker = JpegConstants.Markers.XFF; this.markerPosition = 0; - this.componentIndex = componentIndex; this.componentsLength = componentsLength; this.restartInterval = restartInterval; this.spectralStart = spectralStart; @@ -176,7 +170,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // Scan an interleaved mcu... process components in order for (int k = 0; k < this.componentsLength; k++) { - JpegComponent component = this.components[k]; + int order = this.frame.ComponentOrder[k]; + JpegComponent component = this.components[order]; ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; ref HuffmanTable acHuffmanTable = ref this.acHuffmanTables[component.ACHuffmanTableId]; @@ -223,14 +218,13 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } /// - /// Non-interleaved data, we just need to process one block at a ti - /// in trivial scanline order - /// number of blocks to do just depends on how many actual "pixels" - /// component has, independent of interleaved MCU blocking and such + /// Non-interleaved data, we just need to process one block at a time in trivial scanline order + /// number of blocks to do just depends on how many actual "pixels" each component has, + /// independent of interleaved MCU blocking and such. /// private void ParseBaselineDataNonInterleaved() { - JpegComponent component = this.components[this.componentIndex]; + JpegComponent component = this.components[this.frame.ComponentOrder[0]]; int w = component.WidthInBlocks; int h = component.HeightInBlocks; @@ -295,7 +289,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // Scan an interleaved mcu... process components in order for (int k = 0; k < this.componentsLength; k++) { - JpegComponent component = this.components[k]; + int order = this.frame.ComponentOrder[k]; + JpegComponent component = this.components[order]; ref HuffmanTable dcHuffmanTable = ref this.dcHuffmanTables[component.DCHuffmanTableId]; int h = component.HorizontalSamplingFactor; int v = component.VerticalSamplingFactor; @@ -344,7 +339,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// private void ParseProgressiveDataNonInterleaved() { - JpegComponent component = this.components[this.componentIndex]; + JpegComponent component = this.components[this.frame.ComponentOrder[0]]; int w = component.WidthInBlocks; int h = component.HeightInBlocks; @@ -729,8 +724,9 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } uint k = LRot(this.codeBuffer, n); - this.codeBuffer = k & ~Bmask[n]; - k &= Bmask[n]; + uint mask = Bmask[n]; + this.codeBuffer = k & ~mask; + k &= mask; this.codeBits -= n; return (int)k; } @@ -839,7 +835,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // that way we don't need to shift inside the loop. uint temp = this.codeBuffer >> 16; int k; - for (k = FastBits + 1; ; k++) + for (k = FastBits + 1; ; ++k) { if (temp < table.MaxCode[k]) { diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index e3b0b4bdc6..22d9cbdee4 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -747,11 +747,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg if (!metadataOnly) { // No need to pool this. They max out at 4 - this.Frame.ComponentIds = new byte[this.Frame.ComponentCount]; - this.Frame.Components = new JpegComponent[this.Frame.ComponentCount]; + this.Frame.ComponentIds = new byte[this.ComponentCount]; + this.Frame.ComponentOrder = new byte[this.ComponentCount]; + this.Frame.Components = new JpegComponent[this.ComponentCount]; this.ColorSpace = this.DeduceJpegColorSpace(); - for (int i = 0; i < this.Frame.ComponentCount; i++) + for (int i = 0; i < this.ComponentCount; i++) { byte hv = this.temp[index + 1]; int h = hv >> 4; @@ -823,10 +824,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg codeLengths.GetSpan(), huffmanValues.GetSpan()); - if (huffmanTableSpec >> 4 != 0) + if (tableType != 0) { // Build a table that decodes both magnitude and value of small ACs in one go. - this.fastACTables.BuildACTableLut(huffmanTableSpec & 15, this.acHuffmanTables); + this.fastACTables.BuildACTableLut(tableIndex, this.acHuffmanTables); } } } @@ -867,6 +868,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg if (selector == id) { componentIndex = j; + break; } } @@ -879,6 +881,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg int tableSpec = this.InputStream.ReadByte(); component.DCHuffmanTableId = tableSpec >> 4; component.ACHuffmanTableId = tableSpec & 15; + this.Frame.ComponentOrder[i] = (byte)componentIndex; } this.InputStream.Read(this.temp, 0, 3); @@ -893,7 +896,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.dcHuffmanTables, this.acHuffmanTables, this.fastACTables, - componentIndex, selectorsCount, this.resetInterval, spectralStart, diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs index 2f041e3ab4..6bc559978c 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Images.cs @@ -44,6 +44,9 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg TestImages.Jpeg.Issues.BadRstProgressive518, TestImages.Jpeg.Issues.MissingFF00ProgressiveBedroom159, TestImages.Jpeg.Issues.DhtHasWrongLength624, + TestImages.Jpeg.Issues.OrderedInterleavedProgressive723A, + TestImages.Jpeg.Issues.OrderedInterleavedProgressive723B, + TestImages.Jpeg.Issues.OrderedInterleavedProgressive723C }; /// diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 309fb1d4ab..fdf586c430 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -156,6 +156,9 @@ namespace SixLabors.ImageSharp.Tests public const string InvalidEOI695 = "Jpg/issues/Issue695-Invalid-EOI.jpg"; public const string ExifResizeOutOfRange696 = "Jpg/issues/Issue696-Resize-Exif-OutOfRange.jpg"; public const string InvalidAPP0721 = "Jpg/issues/Issue721-InvalidAPP0.jpg"; + public const string OrderedInterleavedProgressive723A = "Jpg/issues/Issue723-Ordered-Interleaved-Progressive-A.jpg"; + public const string OrderedInterleavedProgressive723B = "Jpg/issues/Issue723-Ordered-Interleaved-Progressive-B.jpg"; + public const string OrderedInterleavedProgressive723C = "Jpg/issues/Issue723-Ordered-Interleaved-Progressive-C.jpg"; } public static readonly string[] All = Baseline.All.Concat(Progressive.All).ToArray(); diff --git a/tests/Images/External b/tests/Images/External index 5f3cbd839f..c0627f384c 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 5f3cbd839fbbffae615d294d1dabafdcabc64cf9 +Subproject commit c0627f384c1d3d2f8d914c9578ae31354c35fd2c diff --git a/tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-A.jpg b/tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-A.jpg new file mode 100644 index 0000000000..13cbb5aa12 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-A.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3909297b3b3427e9836906e324ca6de64614f6da6290e2fa9bb1a0280b118f72 +size 42798 diff --git a/tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-B.jpg b/tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-B.jpg new file mode 100644 index 0000000000..11657617e8 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-B.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4db53948af79218d106a7574f7159468fd2831828ae44e33009f57dc9ab9c07b +size 36937 diff --git a/tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-C.jpg b/tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-C.jpg new file mode 100644 index 0000000000..c1c92e0dc8 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/Issue723-Ordered-Interleaved-Progressive-C.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:cf1c68bec39d39f9caabbf66cf361078a684cb3ae3a1b30509ad12484cae4783 +size 46799 From bc5010bfbb898c9fb2df8abd28e1717c5443519e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Oct 2018 10:11:05 +0100 Subject: [PATCH 140/185] Clean up Huffman table code. --- .../Jpeg/Components/Decoder/FastACTables.cs | 8 +- .../Jpeg/Components/Decoder/HuffmanTable.cs | 104 ++++++++---------- 2 files changed, 52 insertions(+), 60 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs index a7ec93eaf7..bfae7fd756 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs @@ -46,19 +46,19 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder { const int FastBits = ScanDecoder.FastBits; Span fastAC = this.tables.GetRowSpan(index); - ref HuffmanTable huffman = ref acHuffmanTables[index]; + ref HuffmanTable huffmanTable = ref acHuffmanTables[index]; int i; for (i = 0; i < (1 << FastBits); i++) { - byte fast = huffman.Lookahead[i]; + byte fast = huffmanTable.Lookahead[i]; fastAC[i] = 0; if (fast < byte.MaxValue) { - int rs = huffman.Values[fast]; + int rs = huffmanTable.Values[fast]; int run = (rs >> 4) & 15; int magbits = rs & 15; - int len = huffman.Sizes[fast]; + int len = huffmanTable.Sizes[fast]; if (magbits != 0 && len + magbits <= FastBits) { diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index a6bf1bd953..ffc4ce9829 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -46,87 +46,79 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// Initializes a new instance of the struct. /// /// The to use for buffer allocations. - /// The code lengths + /// The code lengths /// The huffman values - public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan count, ReadOnlySpan values) + public HuffmanTable(MemoryAllocator memoryAllocator, ReadOnlySpan codeLengths, ReadOnlySpan values) { const int Length = 257; using (IMemoryOwner huffcode = memoryAllocator.Allocate(Length)) { ref short huffcodeRef = ref MemoryMarshal.GetReference(huffcode.GetSpan()); + ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths); // Figure C.1: make table of Huffman code length for each symbol - fixed (short* sizesRef = this.Sizes.Data) + ref short sizesRef = ref this.Sizes.Data[0]; + short x = 0; + + for (short i = 1; i < 17; i++) { - short x = 0; - for (short i = 1; i < 17; i++) + byte length = Unsafe.Add(ref codeLengthsRef, i); + for (short j = 0; j < length; j++) { - byte l = count[i]; - for (short j = 0; j < l; j++) - { - sizesRef[x++] = i; - } + Unsafe.Add(ref sizesRef, x++) = i; } + } - sizesRef[x] = 0; + Unsafe.Add(ref sizesRef, x) = 0; - // Figure C.2: generate the codes themselves - int k = 0; - fixed (int* valOffsetRef = this.ValOffset.Data) - fixed (uint* maxcodeRef = this.MaxCode.Data) + // Figure C.2: generate the codes themselves + int si = 0; + ref int valOffsetRef = ref this.ValOffset.Data[0]; + ref uint maxcodeRef = ref this.MaxCode.Data[0]; + + uint code = 0; + int k; + for (k = 1; k < 17; k++) + { + // Compute delta to add to code to compute symbol id. + Unsafe.Add(ref valOffsetRef, k) = (int)(si - code); + if (Unsafe.Add(ref sizesRef, si) == k) { - uint code = 0; - int j; - for (j = 1; j < 17; j++) + while (Unsafe.Add(ref sizesRef, si) == k) { - // Compute delta to add to code to compute symbol id. - valOffsetRef[j] = (int)(k - code); - if (sizesRef[k] == j) - { - while (sizesRef[k] == j) - { - Unsafe.Add(ref huffcodeRef, k++) = (short)code++; - } - } - - // Figure F.15: generate decoding tables for bit-sequential decoding. - // Compute largest code + 1 for this size. preshifted as need later. - maxcodeRef[j] = code << (16 - j); - code <<= 1; + Unsafe.Add(ref huffcodeRef, si++) = (short)code++; } - - maxcodeRef[j] = 0xFFFFFFFF; } - // Generate non-spec lookup tables to speed up decoding. - fixed (byte* lookaheadRef = this.Lookahead.Data) - { - const int FastBits = ScanDecoder.FastBits; - var fast = new Span(lookaheadRef, 1 << FastBits); - fast.Fill(0xFF); // Flag for non-accelerated + // Figure F.15: generate decoding tables for bit-sequential decoding. + // Compute largest code + 1 for this size. preshifted as we need later. + Unsafe.Add(ref maxcodeRef, k) = code << (16 - k); + code <<= 1; + } + + Unsafe.Add(ref maxcodeRef, k) = 0xFFFFFFFF; - for (int i = 0; i < k; i++) + // Generate non-spec lookup tables to speed up decoding. + const int FastBits = ScanDecoder.FastBits; + ref byte fastRef = ref this.Lookahead.Data[0]; + new Span(Unsafe.AsPointer(ref fastRef), 1 << FastBits).Fill(0xFF); // Flag for non-accelerated + + for (int i = 0; i < si; i++) + { + int size = Unsafe.Add(ref sizesRef, i); + if (size <= FastBits) + { + int c = Unsafe.Add(ref huffcodeRef, i) << (FastBits - size); + int m = 1 << (FastBits - size); + for (int l = 0; l < m; l++) { - int s = sizesRef[i]; - if (s <= ScanDecoder.FastBits) - { - int c = Unsafe.Add(ref huffcodeRef, i) << (FastBits - s); - int m = 1 << (FastBits - s); - for (int j = 0; j < m; j++) - { - fast[c + j] = (byte)i; - } - } + Unsafe.Add(ref fastRef, c + l) = (byte)i; } } } } - fixed (byte* huffValRef = this.Values.Data) - { - var huffValSpan = new Span(huffValRef, 256); - values.CopyTo(huffValSpan); - } + values.CopyTo(new Span(Unsafe.AsPointer(ref this.Values.Data[0]), 256)); } } } \ No newline at end of file From c10ba1280f14f23cde716578c2435ab12842de61 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Oct 2018 21:42:42 +0100 Subject: [PATCH 141/185] Remove fixed structs. 7.3 can index fixed arrays! --- .../Jpeg/Components/Decoder/FastACTables.cs | 2 +- .../Components/Decoder/FixedByteBuffer256.cs | 24 ------------------- .../Components/Decoder/FixedByteBuffer512.cs | 24 ------------------- .../Components/Decoder/FixedInt16Buffer257.cs | 24 ------------------- .../Components/Decoder/FixedInt32Buffer18.cs | 24 ------------------- .../Components/Decoder/FixedUInt32Buffer18.cs | 24 ------------------- .../Jpeg/Components/Decoder/HuffmanTable.cs | 24 +++++++++---------- .../Jpeg/Components/Decoder/ScanDecoder.cs | 4 ++-- 8 files changed, 15 insertions(+), 135 deletions(-) delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedByteBuffer256.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedByteBuffer512.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedInt16Buffer257.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedInt32Buffer18.cs delete mode 100644 src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedUInt32Buffer18.cs diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs index bfae7fd756..06b46746a6 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FastACTables.cs @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// The table index. /// The collection of AC Huffman tables. - public void BuildACTableLut(int index, HuffmanTables acHuffmanTables) + public unsafe void BuildACTableLut(int index, HuffmanTables acHuffmanTables) { const int FastBits = ScanDecoder.FastBits; Span fastAC = this.tables.GetRowSpan(index); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedByteBuffer256.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedByteBuffer256.cs deleted file mode 100644 index 1d26178e0c..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedByteBuffer256.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder -{ - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct FixedByteBuffer256 - { - public fixed byte Data[256]; - - public byte this[int idx] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ref byte self = ref Unsafe.As(ref this); - return Unsafe.Add(ref self, idx); - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedByteBuffer512.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedByteBuffer512.cs deleted file mode 100644 index 556e74fd58..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedByteBuffer512.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder -{ - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct FixedByteBuffer512 - { - public fixed byte Data[1 << ScanDecoder.FastBits]; - - public byte this[int idx] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ref byte self = ref Unsafe.As(ref this); - return Unsafe.Add(ref self, idx); - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedInt16Buffer257.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedInt16Buffer257.cs deleted file mode 100644 index a3b67a700b..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedInt16Buffer257.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder -{ - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct FixedInt16Buffer257 - { - public fixed short Data[257]; - - public short this[int idx] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ref short self = ref Unsafe.As(ref this); - return Unsafe.Add(ref self, idx); - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedInt32Buffer18.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedInt32Buffer18.cs deleted file mode 100644 index bba89f072f..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedInt32Buffer18.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder -{ - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct FixedInt32Buffer18 - { - public fixed int Data[18]; - - public int this[int idx] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ref int self = ref Unsafe.As(ref this); - return Unsafe.Add(ref self, idx); - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedUInt32Buffer18.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedUInt32Buffer18.cs deleted file mode 100644 index 1d3ca99338..0000000000 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/FixedUInt32Buffer18.cs +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder -{ - [StructLayout(LayoutKind.Sequential)] - internal unsafe struct FixedUInt32Buffer18 - { - public fixed uint Data[18]; - - public uint this[int idx] - { - [MethodImpl(MethodImplOptions.AggressiveInlining)] - get - { - ref uint self = ref Unsafe.As(ref this); - return Unsafe.Add(ref self, idx); - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index ffc4ce9829..08e8604f17 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -20,27 +20,27 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Gets the max code array /// - public FixedUInt32Buffer18 MaxCode; + public fixed uint MaxCode[18]; /// /// Gets the value offset array /// - public FixedInt32Buffer18 ValOffset; + public fixed int ValOffset[18]; /// /// Gets the huffman value array /// - public FixedByteBuffer256 Values; + public fixed byte Values[256]; /// /// Gets the lookahead array /// - public FixedByteBuffer512 Lookahead; + public fixed byte Lookahead[512]; /// /// Gets the sizes array /// - public FixedInt16Buffer257 Sizes; + public fixed short Sizes[257]; /// /// Initializes a new instance of the struct. @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder ref byte codeLengthsRef = ref MemoryMarshal.GetReference(codeLengths); // Figure C.1: make table of Huffman code length for each symbol - ref short sizesRef = ref this.Sizes.Data[0]; + ref short sizesRef = ref this.Sizes[0]; short x = 0; for (short i = 1; i < 17; i++) @@ -73,8 +73,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // Figure C.2: generate the codes themselves int si = 0; - ref int valOffsetRef = ref this.ValOffset.Data[0]; - ref uint maxcodeRef = ref this.MaxCode.Data[0]; + ref int valOffsetRef = ref this.ValOffset[0]; + ref uint maxcodeRef = ref this.MaxCode[0]; uint code = 0; int k; @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } // Figure F.15: generate decoding tables for bit-sequential decoding. - // Compute largest code + 1 for this size. preshifted as we need later. + // Compute largest code + 1 for this size. preshifted as we needit later. Unsafe.Add(ref maxcodeRef, k) = code << (16 - k); code <<= 1; } @@ -100,8 +100,8 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder // Generate non-spec lookup tables to speed up decoding. const int FastBits = ScanDecoder.FastBits; - ref byte fastRef = ref this.Lookahead.Data[0]; - new Span(Unsafe.AsPointer(ref fastRef), 1 << FastBits).Fill(0xFF); // Flag for non-accelerated + ref byte fastRef = ref this.Lookahead[0]; + Unsafe.InitBlockUnaligned(ref fastRef, 0xFF, 1 << FastBits); // Flag for non-accelerated for (int i = 0; i < si; i++) { @@ -118,7 +118,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } } - values.CopyTo(new Span(Unsafe.AsPointer(ref this.Values.Data[0]), 256)); + values.CopyTo(new Span(Unsafe.AsPointer(ref this.Values[0]), 256)); } } } \ No newline at end of file diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs index 6741ccdac2..351e453484 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ScanDecoder.cs @@ -800,7 +800,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } [MethodImpl(InliningOptions.ShortMethod)] - private int DecodeHuffman(ref HuffmanTable table) + private unsafe int DecodeHuffman(ref HuffmanTable table) { this.CheckBits(); @@ -825,7 +825,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } [MethodImpl(InliningOptions.ColdPath)] - private int DecodeHuffmanSlow(ref HuffmanTable table) + private unsafe int DecodeHuffmanSlow(ref HuffmanTable table) { // Naive test is to shift the code_buffer down so k bits are // valid, then test against MaxCode. To speed this up, we've From af4c9dd5836b233b1e2fe8c94fd7885452ce6af3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Oct 2018 22:01:56 +0100 Subject: [PATCH 142/185] Add comment --- src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index 08e8604f17..3f40068f0f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -118,6 +118,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } } + // Ok to use pointer here as struct is declared in method stack space so are essentially pinned. values.CopyTo(new Span(Unsafe.AsPointer(ref this.Values[0]), 256)); } } From 6f791d3e85db92d7eb5e2c1ab099ca9647bde2a8 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Oct 2018 22:28:48 +0100 Subject: [PATCH 143/185] No pointers! --- src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs index 3f40068f0f..24d570bf1c 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/HuffmanTable.cs @@ -118,8 +118,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder } } - // Ok to use pointer here as struct is declared in method stack space so are essentially pinned. - values.CopyTo(new Span(Unsafe.AsPointer(ref this.Values[0]), 256)); + Unsafe.CopyBlockUnaligned(ref this.Values[0], ref MemoryMarshal.GetReference(values), 256); } } } \ No newline at end of file From acb81023886f7574352f39c8d49f17e2e07da056 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 6 Oct 2018 13:08:15 +0100 Subject: [PATCH 144/185] Throw when crop rectangle exceeds source bounds. --- ColorSpaceGenerator/ColorSpaceGenerator.csproj | 1 - src/ImageSharp/Processing/CropExtensions.cs | 2 +- .../Processors/Transforms/CropProcessor.cs | 7 +++++-- .../Processors/Transforms/EntropyCropProcessor.cs | 2 +- .../BaseImageOperationsExtensionTest.cs | 8 +++++--- tests/ImageSharp.Tests/ImageOperationTests.cs | 13 +++++-------- .../Processing/Transforms/CropTest.cs | 8 ++++++++ 7 files changed, 25 insertions(+), 16 deletions(-) delete mode 100644 ColorSpaceGenerator/ColorSpaceGenerator.csproj diff --git a/ColorSpaceGenerator/ColorSpaceGenerator.csproj b/ColorSpaceGenerator/ColorSpaceGenerator.csproj deleted file mode 100644 index 7727272f8f..0000000000 --- a/ColorSpaceGenerator/ColorSpaceGenerator.csproj +++ /dev/null @@ -1 +0,0 @@ - diff --git a/src/ImageSharp/Processing/CropExtensions.cs b/src/ImageSharp/Processing/CropExtensions.cs index 34c754a08e..1c0d80afc9 100644 --- a/src/ImageSharp/Processing/CropExtensions.cs +++ b/src/ImageSharp/Processing/CropExtensions.cs @@ -35,6 +35,6 @@ namespace SixLabors.ImageSharp.Processing /// The public static IImageProcessingContext Crop(this IImageProcessingContext source, Rectangle cropRectangle) where TPixel : struct, IPixel - => source.ApplyProcessor(new CropProcessor(cropRectangle)); + => source.ApplyProcessor(new CropProcessor(cropRectangle, source.GetCurrentSize())); } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs index 8e6a826fd3..3b1d7e94dd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/CropProcessor.cs @@ -22,8 +22,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Initializes a new instance of the class. /// /// The target cropped rectangle. - public CropProcessor(Rectangle cropRectangle) + /// The source image size. + public CropProcessor(Rectangle cropRectangle, Size sourceSize) { + // Check bounds here and throw if we are passed a rectangle exceeding our source bounds. + Guard.IsTrue(new Rectangle(Point.Empty, sourceSize).Contains(cropRectangle), nameof(cropRectangle), "Crop rectangle should be smaller than the source bounds."); this.CropRectangle = cropRectangle; } @@ -53,7 +56,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } - var rect = Rectangle.Intersect(this.CropRectangle, sourceRectangle); + Rectangle rect = this.CropRectangle; // Copying is cheap, we should process more pixels per task: ParallelExecutionSettings parallelSettings = configuration.GetParallelSettings().MultiplyMinimumPixelsPerTask(4); diff --git a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs index 8eeae5d1fc..6de717afd9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/EntropyCropProcessor.cs @@ -62,7 +62,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms rectangle = ImageMaths.GetFilteredBoundingRectangle(temp, 0); } - new CropProcessor(rectangle).Apply(source, sourceRectangle); + new CropProcessor(rectangle, source.Size()).Apply(source, sourceRectangle); } /// diff --git a/tests/ImageSharp.Tests/BaseImageOperationsExtensionTest.cs b/tests/ImageSharp.Tests/BaseImageOperationsExtensionTest.cs index 34b2f718ee..7adbefb346 100644 --- a/tests/ImageSharp.Tests/BaseImageOperationsExtensionTest.cs +++ b/tests/ImageSharp.Tests/BaseImageOperationsExtensionTest.cs @@ -14,7 +14,9 @@ namespace SixLabors.ImageSharp.Tests private readonly FakeImageOperationsProvider.FakeImageOperations internalOperations; protected readonly Rectangle rect; protected readonly GraphicsOptions options; - private Image source; + private readonly Image source; + + public Rectangle SourceBounds() => this.source.Bounds(); public BaseImageOperationsExtensionTest() { @@ -29,7 +31,7 @@ namespace SixLabors.ImageSharp.Tests { Assert.InRange(index, 0, this.internalOperations.Applied.Count - 1); - var operation = this.internalOperations.Applied[index]; + FakeImageOperationsProvider.FakeImageOperations.AppliedOperation operation = this.internalOperations.Applied[index]; return Assert.IsType(operation.Processor); } @@ -38,7 +40,7 @@ namespace SixLabors.ImageSharp.Tests { Assert.InRange(index, 0, this.internalOperations.Applied.Count - 1); - var operation = this.internalOperations.Applied[index]; + FakeImageOperationsProvider.FakeImageOperations.AppliedOperation operation = this.internalOperations.Applied[index]; Assert.Equal(rect, operation.Rectangle); return Assert.IsType(operation.Processor); diff --git a/tests/ImageSharp.Tests/ImageOperationTests.cs b/tests/ImageSharp.Tests/ImageOperationTests.cs index d73eea6870..869882f672 100644 --- a/tests/ImageSharp.Tests/ImageOperationTests.cs +++ b/tests/ImageSharp.Tests/ImageOperationTests.cs @@ -56,7 +56,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void CloneCallsImageOperationsProvider_Func_WithDuplicateImage() { - var returned = this.image.Clone(x => x.ApplyProcessor(this.processor)); + Image returned = this.image.Clone(x => x.ApplyProcessor(this.processor)); Assert.True(this.provider.HasCreated(returned)); Assert.Contains(this.processor, this.provider.AppliedOperations(returned).Select(x => x.Processor)); @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void CloneCallsImageOperationsProvider_ListOfProcessors_WithDuplicateImage() { - var returned = this.image.Clone(this.processor); + Image returned = this.image.Clone(this.processor); Assert.True(this.provider.HasCreated(returned)); Assert.Contains(this.processor, this.provider.AppliedOperations(returned).Select(x => x.Processor)); @@ -74,7 +74,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void CloneCallsImageOperationsProvider_Func_NotOnOrigional() { - var returned = this.image.Clone(x => x.ApplyProcessor(this.processor)); + Image returned = this.image.Clone(x => x.ApplyProcessor(this.processor)); Assert.False(this.provider.HasCreated(this.image)); Assert.DoesNotContain(this.processor, this.provider.AppliedOperations(this.image).Select(x => x.Processor)); } @@ -82,7 +82,7 @@ namespace SixLabors.ImageSharp.Tests [Fact] public void CloneCallsImageOperationsProvider_ListOfProcessors_NotOnOrigional() { - var returned = this.image.Clone(this.processor); + Image returned = this.image.Clone(this.processor); Assert.False(this.provider.HasCreated(this.image)); Assert.DoesNotContain(this.processor, this.provider.AppliedOperations(this.image).Select(x => x.Processor)); } @@ -95,9 +95,6 @@ namespace SixLabors.ImageSharp.Tests Assert.Contains(this.processor, operations.Applied.Select(x => x.Processor)); } - public void Dispose() - { - this.image.Dispose(); - } + public void Dispose() => this.image.Dispose(); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs b/tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs index 154167f15f..6731debd36 100644 --- a/tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Transforms/CropTest.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; @@ -33,5 +34,12 @@ namespace SixLabors.ImageSharp.Tests.Processing.Transforms Assert.Equal(cropRectangle, processor.CropRectangle); } + + [Fact] + public void CropRectangleWithInvalidBoundsThrowsException() + { + var cropRectangle = Rectangle.Inflate(this.SourceBounds(), 5, 5); + Assert.Throws(() => this.operations.Crop(cropRectangle)); + } } } \ No newline at end of file From 1ce14f875effd5290f8c6ff1079c133f9cf163ed Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 6 Oct 2018 13:28:27 +0100 Subject: [PATCH 145/185] Remove invalid test --- .../Processing/Processors/Transforms/CropTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs index 2f78915120..c01c3b1bd3 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/CropTest.cs @@ -17,7 +17,6 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { [Theory] [WithTestPatternImages(70, 30, PixelTypes.Rgba32, 0, 0, 70, 30)] - [WithTestPatternImages(50, 50, PixelTypes.Rgba32, -1, -1, 100, 200)] [WithTestPatternImages(30, 70, PixelTypes.Rgba32, 7, 13, 20, 50)] public void Crop(TestImageProvider provider, int x, int y, int w, int h) where TPixel : struct, IPixel From 8f7ef87fb3ae70edd924d7668067a0fae2178aab Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 6 Oct 2018 16:27:27 +0200 Subject: [PATCH 146/185] new generator methods (cherry picked from commit b116368137d044251ddc3b6879a0b43f3f964494) --- .../PixelOperations{TPixel}.Generated.cs | 43 ++++++------ .../PixelOperations{TPixel}.Generated.tt | 65 +++++++++++++++++-- 2 files changed, 80 insertions(+), 28 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index f644fbefb5..c000b26469 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -24,13 +24,13 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgba = new Rgba64(0, 0, 0, 65535); + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgba = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba64(rgba); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba64(temp); } } @@ -95,13 +95,13 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgb = default(Rgb48); + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgb = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgb48(rgb); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgb48(temp); } } @@ -166,13 +166,13 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgba = new Rgba32(0, 0, 0, 255); + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgba = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(rgba); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba32(temp); } } @@ -237,13 +237,13 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var bgra = new Bgra32(0, 0, 0, 255); + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - bgra = Unsafe.Add(ref sourceRef, i); - dp.PackFromBgra32(bgra); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromBgra32(temp); } } @@ -308,13 +308,13 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgba = new Rgba32(0, 0, 0, 255); + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgba.Rgb = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(rgba); + temp.Rgb = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba32(temp); } } @@ -379,13 +379,13 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var rgba = new Rgba32(0, 0, 0, 255); + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - rgba.Bgr = Unsafe.Add(ref sourceRef, i); - dp.PackFromRgba32(rgba); + temp.Bgr = Unsafe.Add(ref sourceRef, i); + dp.PackFromRgba32(temp); } } @@ -450,13 +450,13 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - var argb = new Argb32(0, 0, 0, 255); + var temp = NamedColors.Black; for (int i = 0; i < count; i++) { ref TPixel dp = ref Unsafe.Add(ref destRef, i); - argb = Unsafe.Add(ref sourceRef, i); - dp.PackFromArgb32(argb); + temp = Unsafe.Add(ref sourceRef, i); + dp.PackFromArgb32(temp); } } @@ -509,4 +509,5 @@ namespace SixLabors.ImageSharp.PixelFormats } } + } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index 1a6ac60f58..0729d02086 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -10,6 +10,49 @@ <#@ import namespace="System.Runtime.InteropServices" #> <#@ output extension=".cs" #> <# + + void GeneratePackFromMethods(string pixelType, string tempPixelType, string assignToTempCode) + { + #> + + /// + /// Converts 'count' elements in 'source` span of data to a span of -s. + /// + /// The source of data. + /// The to the destination pixels. + /// The number of pixels to convert. + internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) + { + GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); + + ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); + ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + + var temp = NamedColors<<#=tempPixelType#>>.Black; + + for (int i = 0; i < count; i++) + { + ref TPixel dp = ref Unsafe.Add(ref destRef, i); + <#=assignToTempCode#> + dp.PackFrom<#=tempPixelType#>(temp); + } + } + + /// + /// A helper for that expects a byte span. + /// The layout of the data in 'sourceBytes' must be compatible with layout. + /// + /// The to the source bytes. + /// The to the destination pixels. + /// The number of pixels to convert. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) + { + this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); + } + <# + } + void GenerateToDestFormatMethods(string pixelType) { #> @@ -276,28 +319,36 @@ namespace SixLabors.ImageSharp.PixelFormats { <# - GeneratePackFromMethodUsingPackFromRgba64("Rgba64", "rgba = Unsafe.Add(ref sourceRef, i);"); + // GeneratePackFromMethodUsingPackFromRgba64("Rgba64", "rgba = Unsafe.Add(ref sourceRef, i);"); + + GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba64"); - GeneratePackFromMethodUsingPackFromRgb48("Rgb48", "rgb = Unsafe.Add(ref sourceRef, i);"); + // GeneratePackFromMethodUsingPackFromRgb48("Rgb48", "rgb = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Rgb48", "Rgb48", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgb48"); - GeneratePackFromMethodUsingPackFromRgba32("Rgba32", "rgba = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Rgba32", "Rgba32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba32"); - GeneratePackFromMethodUsingPackFromBgra32("Bgra32", "bgra = Unsafe.Add(ref sourceRef, i);"); + // GeneratePackFromMethodUsingPackFromBgra32("Bgra32", "bgra = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Bgra32", "Bgra32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Bgra32"); - GeneratePackFromMethodUsingPackFromRgba32("Rgb24", "rgba.Rgb = Unsafe.Add(ref sourceRef, i);"); + // GeneratePackFromMethodUsingPackFromRgba32("Rgb24", "rgba.Rgb = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Rgb24", "Rgba32", "temp.Rgb = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgb24"); - GeneratePackFromMethodUsingPackFromRgba32("Bgr24", "rgba.Bgr = Unsafe.Add(ref sourceRef, i);"); + // GeneratePackFromMethodUsingPackFromRgba32("Bgr24", "rgba.Bgr = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Bgr24", "Rgba32", "temp.Bgr = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Bgr24"); - GeneratePackFromMethodUsingPackFromArgb32("Argb32", "argb = Unsafe.Add(ref sourceRef, i);"); + // GeneratePackFromMethodUsingPackFromArgb32("Argb32", "argb = Unsafe.Add(ref sourceRef, i);"); + GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Argb32"); #> } + } \ No newline at end of file From 006e9247201e0ce59c72ded46a48cc4d55bb90db Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sat, 6 Oct 2018 16:50:40 +0200 Subject: [PATCH 147/185] drop old generators (cherry picked from commit 003bf21c50b8e6628ca68440b66a7d9edc0a2d7f) --- .../PixelOperations{TPixel}.Generated.cs | 7 + .../PixelOperations{TPixel}.Generated.tt | 220 +----------------- 2 files changed, 8 insertions(+), 219 deletions(-) diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs index c000b26469..e8908fe05e 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.cs @@ -24,6 +24,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! var temp = NamedColors.Black; for (int i = 0; i < count; i++) @@ -95,6 +96,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! var temp = NamedColors.Black; for (int i = 0; i < count; i++) @@ -166,6 +168,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! var temp = NamedColors.Black; for (int i = 0; i < count; i++) @@ -237,6 +240,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! var temp = NamedColors.Black; for (int i = 0; i < count; i++) @@ -308,6 +312,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! var temp = NamedColors.Black; for (int i = 0; i < count; i++) @@ -379,6 +384,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! var temp = NamedColors.Black; for (int i = 0; i < count; i++) @@ -450,6 +456,7 @@ namespace SixLabors.ImageSharp.PixelFormats ref Argb32 sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! var temp = NamedColors.Black; for (int i = 0; i < count; i++) diff --git a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt index 0729d02086..5c762c7df1 100644 --- a/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/Generated/PixelOperations{TPixel}.Generated.tt @@ -28,6 +28,7 @@ ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + // For conversion methods writing only to RGB channels, we need to keep the alpha channel opaque! var temp = NamedColors<<#=tempPixelType#>>.Black; for (int i = 0; i < count; i++) @@ -94,216 +95,6 @@ <# } - void GeneratePackFromMethodUsingPackFromRgba64(string pixelType, string rgbaOperationCode) - { - #> - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - var rgba = new Rgba64(0, 0, 0, 65535); - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=rgbaOperationCode#> - dp.PackFromRgba64(rgba); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); - } - <# - } - - void GeneratePackFromMethodUsingPackFromRgb48(string pixelType, string rgbaOperationCode) - { - #> - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - var rgb = default(Rgb48); - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=rgbaOperationCode#> - dp.PackFromRgb48(rgb); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); - } - <# - } - - void GeneratePackFromMethodUsingPackFromRgba32(string pixelType, string rgbaOperationCode) - { - #> - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - var rgba = new Rgba32(0, 0, 0, 255); - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=rgbaOperationCode#> - dp.PackFromRgba32(rgba); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); - } - <# - } - - void GeneratePackFromMethodUsingPackFromArgb32(string pixelType, string argbOperationCode) - { - #> - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - var argb = new Argb32(0, 0, 0, 255); - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=argbOperationCode#> - dp.PackFromArgb32(argb); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); - } - <# - } - - void GeneratePackFromMethodUsingPackFromBgra32(string pixelType, string bgraOperationCode) - { - #> - - /// - /// Converts 'count' elements in 'source` span of data to a span of -s. - /// - /// The source of data. - /// The to the destination pixels. - /// The number of pixels to convert. - internal virtual void PackFrom<#=pixelType#>(ReadOnlySpan<<#=pixelType#>> source, Span destPixels, int count) - { - GuardSpans(source, nameof(source), destPixels, nameof(destPixels), count); - - ref <#=pixelType#> sourceRef = ref MemoryMarshal.GetReference(source); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); - - var bgra = new Bgra32(0, 0, 0, 255); - - for (int i = 0; i < count; i++) - { - ref TPixel dp = ref Unsafe.Add(ref destRef, i); - <#=bgraOperationCode#> - dp.PackFromBgra32(bgra); - } - } - - /// - /// A helper for that expects a byte span. - /// The layout of the data in 'sourceBytes' must be compatible with layout. - /// - /// The to the source bytes. - /// The to the destination pixels. - /// The number of pixels to convert. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal void PackFrom<#=pixelType#>Bytes(ReadOnlySpan sourceBytes, Span destPixels, int count) - { - this.PackFrom<#=pixelType#>(MemoryMarshal.Cast>(sourceBytes), destPixels, count); - } - <# - } - #> // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. @@ -318,35 +109,26 @@ namespace SixLabors.ImageSharp.PixelFormats public partial class PixelOperations { <# - - // GeneratePackFromMethodUsingPackFromRgba64("Rgba64", "rgba = Unsafe.Add(ref sourceRef, i);"); - GeneratePackFromMethods("Rgba64", "Rgba64", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba64"); - // GeneratePackFromMethodUsingPackFromRgb48("Rgb48", "rgb = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Rgb48", "Rgb48", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgb48"); GeneratePackFromMethods("Rgba32", "Rgba32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgba32"); - // GeneratePackFromMethodUsingPackFromBgra32("Bgra32", "bgra = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Bgra32", "Bgra32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Bgra32"); - // GeneratePackFromMethodUsingPackFromRgba32("Rgb24", "rgba.Rgb = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Rgb24", "Rgba32", "temp.Rgb = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Rgb24"); - // GeneratePackFromMethodUsingPackFromRgba32("Bgr24", "rgba.Bgr = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Bgr24", "Rgba32", "temp.Bgr = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Bgr24"); - // GeneratePackFromMethodUsingPackFromArgb32("Argb32", "argb = Unsafe.Add(ref sourceRef, i);"); GeneratePackFromMethods("Argb32", "Argb32", "temp = Unsafe.Add(ref sourceRef, i);"); GenerateToDestFormatMethods("Argb32"); - #> } From 18e2e9ce9aa0e55ab5b38ede89f87958c69193db Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Sv=C3=A5n=C3=A5?= Date: Sat, 6 Oct 2018 21:32:43 +0200 Subject: [PATCH 148/185] -Remove ResizeProcess.EnsureSizeBothDimensions and inlined its functionality in the constructors. -Updated ResizeExtensions remarks. --- .../Processors/Transforms/ResizeProcessor.cs | 63 +++++++------------ src/ImageSharp/Processing/ResizeExtensions.cs | 20 +++--- 2 files changed, 32 insertions(+), 51 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 2f1ef68652..53cd9e9d3e 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -45,7 +45,21 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // Ensure size is populated across both dimensions. // These dimensions are used to calculate the final dimensions determined by the mode algorithm. - EnsureSizeBothDimensions(sourceSize.Width, sourceSize.Height, ref targetWidth, ref targetHeight, out _, out _); + // If only one of the incoming dimensions is 0, it will be modified here to maintain aspect ratio. + // If it is not possible to keep aspect ratio, make sure at least the minimum is is kept. + const int min = 1; + if (targetWidth == 0 && targetHeight > 0) + { + targetWidth = (int)MathF.Max(min, MathF.Round(sourceSize.Width * targetHeight / (float)sourceSize.Height)); + } + + if (targetHeight == 0 && targetWidth > 0) + { + targetHeight = (int)MathF.Max(min, MathF.Round(sourceSize.Height * targetWidth / (float)sourceSize.Width)); + } + + Guard.MustBeGreaterThan(targetWidth, 0, nameof(targetWidth)); + Guard.MustBeGreaterThan(targetHeight, 0, nameof(targetHeight)); (Size size, Rectangle rectangle) = ResizeHelper.CalculateTargetLocationAndBounds(sourceSize, options, targetWidth, targetHeight); @@ -84,14 +98,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Guard.NotNull(sampler, nameof(sampler)); // Ensure size is populated across both dimensions. - EnsureSizeBothDimensions(sourceSize.Width, sourceSize.Height, ref width, ref height, out bool changedWidth, out bool changedHeight); - if (changedWidth) + // If only one of the incoming dimensions is 0, it will be modified here to maintain aspect ratio. + // If it is not possible to keep aspect ratio, make sure at least the minimum is is kept. + const int min = 1; + if (width == 0 && height > 0) { + width = (int)MathF.Max(min, MathF.Round(sourceSize.Width * height / (float)sourceSize.Height)); resizeRectangle.Width = width; } - if (changedHeight) + if (height == 0 && width > 0) { + height = (int)MathF.Max(min, MathF.Round(sourceSize.Height * width / (float)sourceSize.Width)); resizeRectangle.Height = height; } @@ -130,43 +148,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// public bool Compand { get; } - /// - /// Makes sure both target dimensions are >= 1. - /// If only one of the incoming dimensions is 0, it will be modified here to maintain aspect ratio. - /// If it is not possible to keep aspect ratio, make sure at least 1 pixel is kept. - /// - private static void EnsureSizeBothDimensions( - int sourceWidth, - int sourceHeight, - ref int targetWidth, - ref int targetHeight, - out bool changedTargetWidth, - out bool changedTargetHeight) - { - if (targetWidth == 0 && targetHeight > 0) - { - targetWidth = Math.Max(1, (int)MathF.Round(sourceWidth * targetHeight / (float)sourceHeight)); - changedTargetWidth = true; - } - else - { - changedTargetWidth = false; - } - - if (targetHeight == 0 && targetWidth > 0) - { - targetHeight = Math.Max(1, (int)MathF.Round(sourceHeight * targetWidth / (float)sourceWidth)); - changedTargetHeight = true; - } - else - { - changedTargetHeight = false; - } - - Guard.MustBeGreaterThan(targetWidth, 0, nameof(targetWidth)); - Guard.MustBeGreaterThan(targetHeight, 0, nameof(targetHeight)); - } - /// /// Computes the weights to apply at each pixel when resizing. /// diff --git a/src/ImageSharp/Processing/ResizeExtensions.cs b/src/ImageSharp/Processing/ResizeExtensions.cs index 8a370db693..7b6c14d7de 100644 --- a/src/ImageSharp/Processing/ResizeExtensions.cs +++ b/src/ImageSharp/Processing/ResizeExtensions.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Processing /// The image to resize. /// The resize options. /// The - /// Passing zero for one of height or width within the resize options will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width within the resize options will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, ResizeOptions options) where TPixel : struct, IPixel => source.ApplyProcessor(new ResizeProcessor(options, source.GetCurrentSize())); @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Processing /// The image to resize. /// The target image size. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, Size size) where TPixel : struct, IPixel => Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, false); @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing /// The target image size. /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, Size size, bool compand) where TPixel : struct, IPixel => Resize(source, size.Width, size.Height, KnownResamplers.Bicubic, compand); @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing /// The target image width. /// The target image height. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height) where TPixel : struct, IPixel => Resize(source, width, height, KnownResamplers.Bicubic, false); @@ -71,7 +71,7 @@ namespace SixLabors.ImageSharp.Processing /// The target image height. /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, bool compand) where TPixel : struct, IPixel => Resize(source, width, height, KnownResamplers.Bicubic, compand); @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.Processing /// The target image height. /// The to perform the resampling. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, IResampler sampler) where TPixel : struct, IPixel => Resize(source, width, height, sampler, false); @@ -99,7 +99,7 @@ namespace SixLabors.ImageSharp.Processing /// The to perform the resampling. /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, Size size, IResampler sampler, bool compand) where TPixel : struct, IPixel => Resize(source, size.Width, size.Height, sampler, new Rectangle(0, 0, size.Width, size.Height), compand); @@ -114,7 +114,7 @@ namespace SixLabors.ImageSharp.Processing /// The to perform the resampling. /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize(this IImageProcessingContext source, int width, int height, IResampler sampler, bool compand) where TPixel : struct, IPixel => Resize(source, width, height, sampler, new Rectangle(0, 0, width, height), compand); @@ -136,7 +136,7 @@ namespace SixLabors.ImageSharp.Processing /// /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize( this IImageProcessingContext source, int width, @@ -161,7 +161,7 @@ namespace SixLabors.ImageSharp.Processing /// /// Whether to compress and expand the image color-space to gamma correct the image during processing. /// The - /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image + /// Passing zero for one of height or width will automatically preserve the aspect ratio of the original image or the nearest possible ratio. public static IImageProcessingContext Resize( this IImageProcessingContext source, int width, From 31bccc671cb8767ad93bcf6fea6fa13d952f1e6c Mon Sep 17 00:00:00 2001 From: Peter Amrehn Date: Sat, 6 Oct 2018 22:23:41 +0200 Subject: [PATCH 149/185] Add ToString implementations to Bgr24 and Bgra32 --- src/ImageSharp/PixelFormats/Bgr24.cs | 6 ++++++ src/ImageSharp/PixelFormats/Bgra32.cs | 6 ++++++ 2 files changed, 12 insertions(+) diff --git a/src/ImageSharp/PixelFormats/Bgr24.cs b/src/ImageSharp/PixelFormats/Bgr24.cs index fc283b5684..1f401f1a13 100644 --- a/src/ImageSharp/PixelFormats/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/Bgr24.cs @@ -197,5 +197,11 @@ namespace SixLabors.ImageSharp.PixelFormats /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public void ToRgba64(ref Rgba64 dest) => dest.PackFromScaledVector4(this.ToScaledVector4()); + + /// + public override string ToString() + { + return $"({this.B},{this.G},{this.R})"; + } } } \ No newline at end of file diff --git a/src/ImageSharp/PixelFormats/Bgra32.cs b/src/ImageSharp/PixelFormats/Bgra32.cs index 233df2f29e..ff52600081 100644 --- a/src/ImageSharp/PixelFormats/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/Bgra32.cs @@ -280,5 +280,11 @@ namespace SixLabors.ImageSharp.PixelFormats this.B = (byte)vector.Z; this.A = (byte)vector.W; } + + /// + public override string ToString() + { + return $"({this.B},{this.G},{this.R},{this.A})"; + } } } \ No newline at end of file From 4ffc58008bc6a9b222ffb4c603edba04d1c2946d Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 00:09:41 +0200 Subject: [PATCH 150/185] LeastCommonMultiple --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 24 +++++++++++++++++ .../Transforms/ResizeProfilingBenchmarks.cs | 27 ++++++++++++++----- .../Processors/Transforms/ResizeTests.cs | 24 +++++++++++++++++ .../ImageProviders/TestImageProvider.cs | 2 +- 4 files changed, 69 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index c15e0a7329..b3a1b4ba39 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -13,6 +13,30 @@ namespace SixLabors.ImageSharp /// internal static class ImageMaths { + /// + /// Determine the Greatest CommonDivisor (GCD) of two numbers. + /// + public static int GreatestCommonDivisor(int a, int b) + { + while (b != 0) + { + int temp = b; + b = a % b; + a = temp; + } + + return a; + } + + /// + /// Determine the Least Common Multiple (LCM) of two numbers. + /// + public static int LeastCommonMultiple(int a, int b) + { + // https://en.wikipedia.org/wiki/Least_common_multiple#Reduction_by_the_greatest_common_divisor + return (a / GreatestCommonDivisor(a, b)) * b; + } + /// /// Returns the absolute value of a 32-bit signed integer. Uses bit shifting to speed up the operation. /// diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs index d5f015404d..4a35d63020 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs @@ -10,6 +10,8 @@ using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Transforms; using SixLabors.Primitives; + +using Xunit; using Xunit.Abstractions; namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms @@ -38,11 +40,19 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms }); } - // [Fact] - public void PrintWeightsData() + [Theory] + [InlineData(500, 200, nameof(KnownResamplers.Bicubic))] + [InlineData(50, 40, nameof(KnownResamplers.Bicubic))] + [InlineData(40, 30, nameof(KnownResamplers.Bicubic))] + [InlineData(500, 200, nameof(KnownResamplers.Lanczos8))] + [InlineData(100, 80, nameof(KnownResamplers.Lanczos8))] + [InlineData(100, 10, nameof(KnownResamplers.Lanczos8))] + [InlineData(10, 100, nameof(KnownResamplers.Lanczos8))] + public void PrintWeightsData(int srcSize, int destSize, string resamplerName) { - var size = new Size(500, 500); - var proc = new ResizeProcessor(KnownResamplers.Bicubic, 200, 200, size); + var size = new Size(srcSize, srcSize); + var resampler = (IResampler) typeof(KnownResamplers).GetProperty(resamplerName).GetValue(null); + var proc = new ResizeProcessor(resampler, destSize, destSize, size); WeightsBuffer weights = proc.PrecomputeWeights(Configuration.Default.MemoryAllocator, proc.Width, size.Width); @@ -54,16 +64,19 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms for (int i = 0; i < window.Length; i++) { float value = span[i]; - bld.Append(value); + bld.Append($"{value,7:F4}"); bld.Append("| "); } bld.AppendLine(); } - File.WriteAllText("BicubicWeights.MD", bld.ToString()); + string outDir = TestEnvironment.CreateOutputDirectory("." + nameof(this.PrintWeightsData)); + string fileName = $@"{outDir}\{resamplerName}_{srcSize}_{destSize}.MD"; + + File.WriteAllText(fileName, bld.ToString()); - // this.Output.WriteLine(bld.ToString()); + this.Output.WriteLine(bld.ToString()); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 746d8da16e..a84adbe1c6 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -56,6 +56,30 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } + [Theory] + [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 1)] + [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 4)] + [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, 8)] + [WithFileCollection(nameof(CommonTestImages), DefaultPixelType, -1)] + public void Resize_WorksWithAllParallelismLevels(TestImageProvider provider, int maxDegreeOfParallelism) + where TPixel : struct, IPixel + { + if (maxDegreeOfParallelism >= 0) + { + provider.Configuration.MaxDegreeOfParallelism = maxDegreeOfParallelism; + } + + using (Image image = provider.GetImage()) + { + SizeF newSize = image.Size() * 0.5f; + image.Mutate(x => x.Resize((Size)newSize, false)); + FormattableString details = $"MDP{maxDegreeOfParallelism}"; + + image.DebugSave(provider, details); + //image.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.005f), provider, details); + } + } + [Theory] [WithTestPatternImages(100, 100, DefaultPixelType)] public void Resize_Compand(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs index 30ac0856c7..5b5e4740a3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestImageProvider.cs @@ -33,7 +33,7 @@ namespace SixLabors.ImageSharp.Tests public virtual string SourceFileOrDescription => ""; - public Configuration Configuration { get; set; } = Configuration.Default.Clone(); + public Configuration Configuration { get; set; } = Configuration.CreateDefaultInstance(); /// /// Utility instance to provide informations about the test image & manage input/output From 7b462e70e9e9036435101ba3cef47d0a4efe187e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 6 Oct 2018 23:10:52 +0100 Subject: [PATCH 151/185] Add additional tests --- .../CieLchAndCieLuvConversionTests.cs | 78 ++++++++++++++++++ .../Conversion/CieLchAndHslConversionTests.cs | 78 ++++++++++++++++++ .../Conversion/CieLchAndHsvConversionTests.cs | 78 ++++++++++++++++++ .../CieLchAndHunterLabConversionTests.cs | 78 ++++++++++++++++++ .../CieLchAndLinearRgbConversionTests.cs | 78 ++++++++++++++++++ .../Conversion/CieLchAndLmsConversionTests.cs | 78 ++++++++++++++++++ .../Conversion/CieLchAndRgbConversionTests.cs | 78 ++++++++++++++++++ .../CieLchAndYCbCrConversionTests.cs | 78 ++++++++++++++++++ .../CieXyzAndCieLchConversionTests.cs | 79 ++++++++++++++++++ .../CieXyzAndCieLchuvConversionTests.cs | 79 ++++++++++++++++++ .../Conversion/CieXyzAndHslConversionTests.cs | 80 +++++++++++++++++++ .../Conversion/CieXyzAndHsvConversionTests.cs | 80 +++++++++++++++++++ .../CieXyzAndYCbCrConversionTests.cs | 80 +++++++++++++++++++ .../Conversion/CmykAndYCbCrConversionTests.cs | 79 ++++++++++++++++++ 14 files changed, 1101 insertions(+) create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..e465757ef7 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndCieLuvConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchAndCieLuvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 34.89777, 187.6642, -7.181467)] + public void Convert_CieLch_to_CieLuv(float l, float c, float h, float l2, float u, float v) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new CieLuv(l2, u, v); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(34.89777, 187.6642, -7.181467, 36.05552, 103.6901, 10.01514)] + public void Convert_CieLuv_to_CieLch(float l2, float u, float v, float l, float c, float h) + { + // Arrange + var input = new CieLuv(l2, u, v); + var expected = new CieLch(l, c, h); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs new file mode 100644 index 0000000000..d00a164c08 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHslConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchAndHslConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 341.959, 1, 0.4207301)] + public void Convert_CieLch_to_Hsl(float l, float c, float h, float h2, float s, float l2) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new Hsl(h2, s, l2); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + var actual = Converter.ToHsl(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(341.959, 1, 0.4207301, 46.13444, 78.0637, 22.90503)] + public void Convert_Hsl_to_CieLch(float h2, float s, float l2, float l, float c, float h) + { + // Arrange + var input = new Hsl(h2, s, l2); + var expected = new CieLch(l, c, h); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs new file mode 100644 index 0000000000..d3ff04a759 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHsvConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchAndHsvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 341.959, 1, 0.8414602)] + public void Convert_CieLch_to_Hsv(float l, float c, float h, float h2, float s, float v) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new Hsv(h2, s, v); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + var actual = Converter.ToHsv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(341.959, 1, 0.8414602, 46.13444, 78.0637, 22.90501)] + public void Convert_Hsv_to_CieLch(float h2, float s, float v, float l, float c, float h) + { + // Arrange + var input = new Hsv(h2, s, v); + var expected = new CieLch(l, c, h); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..852e56110b --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndHunterLabConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchAndHunterLabConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 29.41358, 106.6302, 9.102425)] + public void Convert_CieLch_to_HunterLab(float l, float c, float h, float l2, float a, float b) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new HunterLab(l2, a, b); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + var actual = Converter.ToHunterLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(29.41358, 106.6302, 9.102425, 36.05551, 103.6901, 10.01515)] + public void Convert_HunterLab_to_CieLch(float l2, float a, float b, float l, float c, float h) + { + // Arrange + var input = new HunterLab(l2, a, b); + var expected = new CieLch(l, c, h); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs new file mode 100644 index 0000000000..80b72cb2c2 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLinearRgbConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchAndLinearRgbConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 0.6765013, 0, 0.05209038)] + public void Convert_CieLch_to_LinearRgb(float l, float c, float h, float r, float g, float b) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new LinearRgb(r, g, b); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new LinearRgb[5]; + + // Act + var actual = Converter.ToLinearRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0.6765013, 0, 0.05209038, 46.13445, 78.06367, 22.90504)] + public void Convert_LinearRgb_to_CieLch(float r, float g, float b, float l, float c, float h) + { + // Arrange + var input = new LinearRgb(r, g, b); + var expected = new CieLch(l, c, h); + + Span inputSpan = new LinearRgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs new file mode 100644 index 0000000000..314734ff2e --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndLmsConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchAndLmsConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 0.2440057, -0.04603009, 0.05780027)] + public void Convert_CieLch_to_Lms(float l, float c, float h, float l2, float m, float s) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new Lms(l2, m, s); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new Lms[5]; + + // Act + var actual = Converter.ToLms(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0.2440057, -0.04603009, 0.05780027, 36.05552, 103.6901, 10.01515)] + public void Convert_Lms_to_CieLch(float l2, float m, float s, float l, float c, float h) + { + // Arrange + var input = new Lms(l2, m, s); + var expected = new CieLch(l, c, h); + + Span inputSpan = new Lms[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs new file mode 100644 index 0000000000..389528dcd3 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndRgbConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchAndRgbConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(36.0555, 103.6901, 10.01514, 0.8414602, 0, 0.2530123)] + public void Convert_CieLch_to_Rgb(float l, float c, float h, float r, float g, float b) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new Rgb(r, g, b); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new Rgb[5]; + + // Act + var actual = Converter.ToRgb(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0.8414602, 0, 0.2530123, 46.13444, 78.0637, 22.90503)] + public void Convert_Rgb_to_CieLch(float r, float g, float b, float l, float c, float h) + { + // Arrange + var input = new Rgb(r, g, b); + var expected = new CieLch(l, c, h); + + Span inputSpan = new Rgb[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..a2bd7eadc7 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieLchAndYCbCrConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieLchAndYCbCrConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(36.0555, 103.6901, 10.01514, 71.5122, 124.053, 230.0401)] + public void Convert_CieLch_to_YCbCr(float l, float c, float h, float y, float cb, float cr) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new YCbCr(y, cb, cr); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + var actual = Converter.ToYCbCr(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(71.5122, 124.053, 230.0401, 46.23178, 78.1114, 22.7662)] + public void Convert_YCbCr_to_CieLch(float y, float cb, float cr, float l, float c, float h) + { + // Arrange + var input = new YCbCr(y, cb, cr); + var expected = new CieLch(l, c, h); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs new file mode 100644 index 0000000000..89d78ece1f --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyzAndCieLchConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0.360555, 0.936901, 0.1001514, 97.50815, 155.8035, 139.323)] + public void Convert_CieXyz_to_CieLch(float x, float y, float yl, float l, float c, float h) + { + // Arrange + var input = new CieXyz(x, y, yl); + var expected = new CieLch(l, c, h); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(97.50815, 155.8035, 139.323, 0.3605551, 0.936901, 0.1001514)] + public void Convert_CieLch_to_CieXyz(float l, float c, float h, float x, float y, float yl) + { + // Arrange + var input = new CieLch(l, c, h); + var expected = new CieXyz(x, y, yl); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + var actual = Converter.ToCieXyz(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs new file mode 100644 index 0000000000..fbd602d9a0 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndCieLchuvConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyzAndCieLchuvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0.360555, 0.936901, 0.1001514, 97.50697, 183.3831, 133.6321)] + public void Convert_CieXyz_to_CieLchuv(float x, float y, float yl, float l, float c, float h) + { + // Arrange + var input = new CieXyz(x, y, yl); + var expected = new CieLchuv(l, c, h); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLchuv[5]; + + // Act + var actual = Converter.ToCieLchuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(97.50697, 183.3831, 133.6321, 0.360555, 0.936901, 0.1001515)] + public void Convert_CieLchuv_to_CieXyz(float l, float c, float h, float x, float y, float yl) + { + // Arrange + var input = new CieLchuv(l, c, h); + var expected = new CieXyz(x, y, yl); + + Span inputSpan = new CieLchuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + var actual = Converter.ToCieXyz(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs new file mode 100644 index 0000000000..8443722641 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHslConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyzAndHslConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.5)] + public void Convert_CieXyz_to_Hsl(float x, float y, float yl, float h, float s, float l) + { + // Arrange + var input = new CieXyz(x, y, yl); + var expected = new Hsl(h, s, l); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + var actual = Converter.ToHsl(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.5, 0.3575761, 0.7151522, 0.119192)] + public void Convert_Hsl_to_CieXyz(float h, float s, float l, float x, float y, float yl) + { + // Arrange + var input = new Hsl(h, s, l); + var expected = new CieXyz(x, y, yl); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + var actual = Converter.ToCieXyz(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs new file mode 100644 index 0000000000..327d660c6c --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndHsvConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyzAndHsvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(0.360555, 0.936901, 0.1001514, 120, 1, 0.9999999)] + public void Convert_CieXyz_to_Hsv(float x, float y, float yl, float h, float s, float v) + { + // Arrange + var input = new CieXyz(x, y, yl); + var expected = new Hsv(h, s, v); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + var actual = Converter.ToHsv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0)] + [InlineData(120, 1, 0.9999999, 0.3575761, 0.7151522, 0.119192)] + public void Convert_Hsv_to_CieXyz(float h, float s, float v, float x, float y, float yl) + { + // Arrange + var input = new Hsv(h, s, v); + var expected = new CieXyz(x, y, yl); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + var actual = Converter.ToCieXyz(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..eacdc7ffba --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CieXyzAndYCbCrConversionTests.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CieXyzAndYCbCrConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 128, 128)] + [InlineData(0.360555, 0.936901, 0.1001514, 149.685, 43.52769, 21.23457)] + public void Convert_CieXyz_to_YCbCr(float x, float y, float z, float y2, float cb, float cr) + { + // Arrange + var input = new CieXyz(x, y, z); + var expected = new YCbCr(y2, cb, cr); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + var actual = Converter.ToYCbCr(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 128, 128, 0, 0, 0)] + [InlineData(149.685, 43.52769, 21.23457, 0.3575761, 0.7151522, 0.119192)] + public void Convert_YCbCr_to_CieXyz(float y2, float cb, float cr, float x, float y, float z) + { + // Arrange + var input = new YCbCr(y2, cb, cr); + var expected = new CieXyz(x, y, z); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + var actual = Converter.ToCieXyz(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs new file mode 100644 index 0000000000..8c45127e3e --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CmykAndYCbCrConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 255, 128, 128)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 136.5134, 69.90555, 114.9948)] + public void Convert_Cmyk_to_YCbCr(float c, float m, float y, float k, float y2, float cb, float cr) + { + // Arrange + var input = new Cmyk(c, m, y, k); + var expected = new YCbCr(y2, cb, cr); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new YCbCr[5]; + + // Act + var actual = Converter.ToYCbCr(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(255, 128, 128, 0, 0, 0, 5.960464E-08)] + [InlineData(136.5134, 69.90555, 114.9948, 0.2891567, 0, 0.7951807, 0.3490196)] + public void Convert_YCbCr_to_Cmyk(float y2, float cb, float cr, float c, float m, float y, float k) + { + // Arrange + var input = new YCbCr(y2, cb, cr); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new YCbCr[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file From e84cdbafcc1444a0feb40c8b31bb3e874dd62a7a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 00:19:26 +0200 Subject: [PATCH 152/185] tests for LCM & GCD --- .../Helpers/ImageMathsTests.cs | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) create mode 100644 tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs new file mode 100644 index 0000000000..41e6b65c56 --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -0,0 +1,40 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Helpers +{ + public class ImageMathsTests + { + [Theory] + [InlineData(1, 1, 1)] + [InlineData(1, 42, 1)] + [InlineData(10, 8, 2)] + [InlineData(12, 18, 6)] + [InlineData(4536, 1000, 8)] + [InlineData(1600, 1024, 64)] + public void GreatestCommonDivisor(int a, int b, int expected) + { + int actual = ImageMaths.GreatestCommonDivisor(a, b); + + Assert.Equal(expected, actual); + } + + [Theory] + [InlineData(1, 1, 1)] + [InlineData(1, 42, 42)] + [InlineData(3, 4, 12)] + [InlineData(6, 4, 12)] + [InlineData(1600, 1024, 25600)] + [InlineData(3264, 100, 81600)] + public void LeastCommonMultiple(int a, int b, int expected) + { + int actual = ImageMaths.LeastCommonMultiple(a, b); + + Assert.Equal(expected, actual); + } + + // TODO: We need to test all ImageMaths methods! + } +} \ No newline at end of file From 607cec8fdbc649906833f178fbf9fa06e6c360ee Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 00:36:45 +0200 Subject: [PATCH 153/185] do not allocate unnecessaryly large buffer in WeightsBuffer --- .../Processors/Transforms/ResizeProcessor.cs | 2 +- .../Processing/Processors/Transforms/WeightsBuffer.cs | 7 ++++--- .../Processing/Processors/Transforms/WeightsWindow.cs | 10 +++++----- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 76abc64996..9b757f6e1b 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -162,7 +162,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms IResampler sampler = this.Sampler; float radius = MathF.Ceiling(scale * sampler.Radius); - var result = new WeightsBuffer(memoryAllocator, sourceSize, destinationSize); + var result = new WeightsBuffer(memoryAllocator, destinationSize, radius); for (int i = 0; i < destinationSize; i++) { diff --git a/src/ImageSharp/Processing/Processors/Transforms/WeightsBuffer.cs b/src/ImageSharp/Processing/Processors/Transforms/WeightsBuffer.cs index 68133a5489..6acf38d119 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/WeightsBuffer.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/WeightsBuffer.cs @@ -19,11 +19,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Initializes a new instance of the class. /// /// The to use for allocations. - /// The size of the source window /// The size of the destination window - public WeightsBuffer(MemoryAllocator memoryAllocator, int sourceSize, int destinationSize) + /// The radius of the kernel + public WeightsBuffer(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) { - this.dataBuffer = memoryAllocator.Allocate2D(sourceSize, destinationSize, AllocationOptions.Clean); + int width = (int)Math.Ceiling(kernelRadius * 2); + this.dataBuffer = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); this.Weights = new WeightsWindow[destinationSize]; } diff --git a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs b/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs index 01cf97e591..56c665c30d 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs @@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The buffer containing the weights values. /// - private readonly MemorySource buffer; + private readonly Memory buffer; /// /// Initializes a new instance of the struct. @@ -47,9 +47,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] internal WeightsWindow(int index, int left, Buffer2D buffer, int length) { - this.flatStartIndex = (index * buffer.Width) + left; + this.flatStartIndex = index * buffer.Width; this.Left = left; - this.buffer = buffer.MemorySource; + this.buffer = buffer.MemorySource.Memory; this.Length = length; } @@ -60,7 +60,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms [MethodImpl(MethodImplOptions.AggressiveInlining)] public ref float GetStartReference() { - Span span = this.buffer.GetSpan(); + Span span = this.buffer.Span; return ref span[this.flatStartIndex]; } @@ -69,7 +69,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span GetWindowSpan() => this.buffer.GetSpan().Slice(this.flatStartIndex, this.Length); + public Span GetWindowSpan() => this.buffer.Span.Slice(this.flatStartIndex, this.Length); /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. From 5fde593c32d7b123883562b3a721d237e44eac2b Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 00:55:10 +0200 Subject: [PATCH 154/185] Better names: WeightsWindow -> ResizeKernel, WeightsBuffer -> KernelMap --- .../Processors/Transforms/KernelMap.cs | 130 ++++++++++++++++++ .../{WeightsWindow.cs => ResizeKernel.cs} | 24 ++-- .../Processors/Transforms/ResizeProcessor.cs | 109 +++------------ .../Processors/Transforms/WeightsBuffer.cs | 56 -------- .../Processors/Transforms/KernelMapTests.cs | 61 ++++++++ .../Transforms/ResizeProfilingBenchmarks.cs | 38 ----- .../Processors/Transforms/ResizeTests.cs | 1 + 7 files changed, 225 insertions(+), 194 deletions(-) create mode 100644 src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs rename src/ImageSharp/Processing/Processors/Transforms/{WeightsWindow.cs => ResizeKernel.cs} (86%) delete mode 100644 src/ImageSharp/Processing/Processors/Transforms/WeightsBuffer.cs create mode 100644 tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs diff --git a/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs new file mode 100644 index 0000000000..277be53fff --- /dev/null +++ b/src/ImageSharp/Processing/Processors/Transforms/KernelMap.cs @@ -0,0 +1,130 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +using SixLabors.ImageSharp.Memory; +using SixLabors.Memory; + +namespace SixLabors.ImageSharp.Processing.Processors.Transforms +{ + /// + /// Holds the values in an optimized contigous memory region. + /// + internal class KernelMap : IDisposable + { + private readonly Buffer2D data; + + /// + /// Initializes a new instance of the class. + /// + /// The to use for allocations. + /// The size of the destination window + /// The radius of the kernel + public KernelMap(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) + { + int width = (int)Math.Ceiling(kernelRadius * 2); + this.data = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); + this.Kernels = new ResizeKernel[destinationSize]; + } + + /// + /// Gets the calculated values. + /// + public ResizeKernel[] Kernels { get; } + + /// + /// Disposes instance releasing it's backing buffer. + /// + public void Dispose() + { + this.data.Dispose(); + } + + /// + /// Computes the weights to apply at each pixel when resizing. + /// + /// The + /// The destination size + /// The source size + /// The to use for buffer allocations + /// The + public static KernelMap Calculate( + IResampler sampler, + int destinationSize, + int sourceSize, + MemoryAllocator memoryAllocator) + { + float ratio = (float)sourceSize / destinationSize; + float scale = ratio; + + if (scale < 1F) + { + scale = 1F; + } + + float radius = MathF.Ceiling(scale * sampler.Radius); + var result = new KernelMap(memoryAllocator, destinationSize, radius); + + for (int i = 0; i < destinationSize; i++) + { + float center = ((i + .5F) * ratio) - .5F; + + // Keep inside bounds. + int left = (int)MathF.Ceiling(center - radius); + if (left < 0) + { + left = 0; + } + + int right = (int)MathF.Floor(center + radius); + if (right > sourceSize - 1) + { + right = sourceSize - 1; + } + + float sum = 0; + + ResizeKernel ws = result.CreateKernel(i, left, right); + result.Kernels[i] = ws; + + ref float weightsBaseRef = ref ws.GetStartReference(); + + for (int j = left; j <= right; j++) + { + float weight = sampler.GetValue((j - center) / scale); + sum += weight; + + // weights[j - left] = weight: + Unsafe.Add(ref weightsBaseRef, j - left) = weight; + } + + // Normalize, best to do it here rather than in the pixel loop later on. + if (sum > 0) + { + for (int w = 0; w < ws.Length; w++) + { + // weights[w] = weights[w] / sum: + ref float wRef = ref Unsafe.Add(ref weightsBaseRef, w); + wRef /= sum; + } + } + } + + return result; + } + + /// + /// Slices a weights value at the given positions. + /// + /// The index in destination buffer + /// The local left index value + /// The local right index value + /// The weights + private ResizeKernel CreateKernel(int destIdx, int leftIdx, int rightIdx) + { + return new ResizeKernel(destIdx, leftIdx, this.data, rightIdx - leftIdx + 1); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs similarity index 86% rename from src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs rename to src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index 56c665c30d..f149523fc7 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/WeightsWindow.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -13,9 +13,9 @@ using SixLabors.Memory; namespace SixLabors.ImageSharp.Processing.Processors.Transforms { /// - /// Points to a collection of of weights allocated in . + /// Points to a collection of of weights allocated in . /// - internal struct WeightsWindow + internal struct ResizeKernel { /// /// The local left index position @@ -38,14 +38,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms private readonly Memory buffer; /// - /// Initializes a new instance of the struct. + /// Initializes a new instance of the struct. /// /// The destination index in the buffer /// The local left index /// The span /// The length of the window [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal WeightsWindow(int index, int left, Buffer2D buffer, int length) + internal ResizeKernel(int index, int left, Buffer2D buffer, int length) { this.flatStartIndex = index * buffer.Width; this.Left = left; @@ -65,20 +65,20 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } /// - /// Gets the span representing the portion of the that this window covers + /// Gets the span representing the portion of the that this window covers /// /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Span GetWindowSpan() => this.buffer.Span.Slice(this.flatStartIndex, this.Length); + public Span GetSpan() => this.buffer.Span.Slice(this.flatStartIndex, this.Length); /// - /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. + /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. /// /// The input span of vectors /// The source row position. /// The weighted sum [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ComputeWeightedRowSum(Span rowSpan, int sourceX) + public Vector4 ConvolvePremultipliedRows(Span rowSpan, int sourceX) { ref float horizontalValues = ref this.GetStartReference(); int left = this.Left; @@ -98,14 +98,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms } /// - /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. + /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. /// Applies to all input vectors. /// /// The input span of vectors /// The source row position. /// The weighted sum [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ComputeExpandedWeightedRowSum(Span rowSpan, int sourceX) + public Vector4 ConvolvePremultipliedExpandedRows(Span rowSpan, int sourceX) { ref float horizontalValues = ref this.GetStartReference(); int left = this.Left; @@ -126,14 +126,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// Computes the sum of vectors in 'firstPassPixels' at a row pointed by 'x', - /// weighted by weight values, pointed by this instance. + /// weighted by weight values, pointed by this instance. /// /// The buffer of input vectors in row first order /// The row position /// The source column position. /// The weighted sum [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ComputeWeightedColumnSum(Buffer2D firstPassPixels, int x, int sourceY) + public Vector4 ConvolveColumnsAndUnPremultiply(Buffer2D firstPassPixels, int x, int sourceY) { ref float verticalValues = ref this.GetStartReference(); int left = this.Left; diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 9b757f6e1b..52ed222cad 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -27,8 +27,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms where TPixel : struct, IPixel { // The following fields are not immutable but are optionally created on demand. - private WeightsBuffer horizontalWeights; - private WeightsBuffer verticalWeights; + private KernelMap horizontalKernelMap; + private KernelMap verticalKernelMap; /// /// Initializes a new instance of the class. @@ -142,75 +142,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// public bool Compand { get; } - /// - /// Computes the weights to apply at each pixel when resizing. - /// - /// The to use for buffer allocations - /// The destination size - /// The source size - /// The - // TODO: Made internal to simplify experimenting with weights data. Make it private when finished figuring out how to optimize all the stuff! - internal WeightsBuffer PrecomputeWeights(MemoryAllocator memoryAllocator, int destinationSize, int sourceSize) - { - float ratio = (float)sourceSize / destinationSize; - float scale = ratio; - - if (scale < 1F) - { - scale = 1F; - } - - IResampler sampler = this.Sampler; - float radius = MathF.Ceiling(scale * sampler.Radius); - var result = new WeightsBuffer(memoryAllocator, destinationSize, radius); - - for (int i = 0; i < destinationSize; i++) - { - float center = ((i + .5F) * ratio) - .5F; - - // Keep inside bounds. - int left = (int)MathF.Ceiling(center - radius); - if (left < 0) - { - left = 0; - } - - int right = (int)MathF.Floor(center + radius); - if (right > sourceSize - 1) - { - right = sourceSize - 1; - } - - float sum = 0; - - WeightsWindow ws = result.GetWeightsWindow(i, left, right); - result.Weights[i] = ws; - - ref float weightsBaseRef = ref ws.GetStartReference(); - - for (int j = left; j <= right; j++) - { - float weight = sampler.GetValue((j - center) / scale); - sum += weight; - - // weights[j - left] = weight: - Unsafe.Add(ref weightsBaseRef, j - left) = weight; - } - - // Normalize, best to do it here rather than in the pixel loop later on. - if (sum > 0) - { - for (int w = 0; w < ws.Length; w++) - { - // weights[w] = weights[w] / sum: - ref float wRef = ref Unsafe.Add(ref weightsBaseRef, w); - wRef /= sum; - } - } - } - - return result; - } /// protected override Image CreateDestination(Image source, Rectangle sourceRectangle) @@ -229,15 +160,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { // Since all image frame dimensions have to be the same we can calculate this for all frames. MemoryAllocator memoryAllocator = source.GetMemoryAllocator(); - this.horizontalWeights = this.PrecomputeWeights( - memoryAllocator, + this.horizontalKernelMap = KernelMap.Calculate( + this.Sampler, this.ResizeRectangle.Width, - sourceRectangle.Width); + sourceRectangle.Width, + memoryAllocator); - this.verticalWeights = this.PrecomputeWeights( - memoryAllocator, + this.verticalKernelMap = KernelMap.Calculate( + this.Sampler, this.ResizeRectangle.Height, - sourceRectangle.Height); + sourceRectangle.Height, + memoryAllocator); } } @@ -326,18 +259,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { for (int x = minX; x < maxX; x++) { - WeightsWindow window = this.horizontalWeights.Weights[x - startX]; + ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; Unsafe.Add(ref firstPassRow, x) = - window.ComputeExpandedWeightedRowSum(tempRowSpan, sourceX); + window.ConvolvePremultipliedExpandedRows(tempRowSpan, sourceX); } } else { for (int x = minX; x < maxX; x++) { - WeightsWindow window = this.horizontalWeights.Weights[x - startX]; + ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; Unsafe.Add(ref firstPassRow, x) = - window.ComputeWeightedRowSum(tempRowSpan, sourceX); + window.ConvolvePremultipliedRows(tempRowSpan, sourceX); } } } @@ -354,7 +287,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int y = rows.Min; y < rows.Max; y++) { // Ensure offsets are normalized for cropping and padding. - WeightsWindow window = this.verticalWeights.Weights[y - startY]; + ResizeKernel window = this.verticalKernelMap.Kernels[y - startY]; ref TPixel targetRow = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); if (this.Compand) @@ -362,7 +295,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = 0; x < width; x++) { // Destination color components - Vector4 destinationVector = window.ComputeWeightedColumnSum( + Vector4 destinationVector = window.ConvolveColumnsAndUnPremultiply( firstPassPixels, x, sourceY); @@ -377,7 +310,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = 0; x < width; x++) { // Destination color components - Vector4 destinationVector = window.ComputeWeightedColumnSum( + Vector4 destinationVector = window.ConvolveColumnsAndUnPremultiply( firstPassPixels, x, sourceY); @@ -396,10 +329,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms base.AfterImageApply(source, destination, sourceRectangle); // TODO: An exception in the processing chain can leave these buffers undisposed. We should consider making image processors IDisposable! - this.horizontalWeights?.Dispose(); - this.horizontalWeights = null; - this.verticalWeights?.Dispose(); - this.verticalWeights = null; + this.horizontalKernelMap?.Dispose(); + this.horizontalKernelMap = null; + this.verticalKernelMap?.Dispose(); + this.verticalKernelMap = null; } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/WeightsBuffer.cs b/src/ImageSharp/Processing/Processors/Transforms/WeightsBuffer.cs deleted file mode 100644 index 6acf38d119..0000000000 --- a/src/ImageSharp/Processing/Processors/Transforms/WeightsBuffer.cs +++ /dev/null @@ -1,56 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; - -using SixLabors.ImageSharp.Memory; -using SixLabors.Memory; - -namespace SixLabors.ImageSharp.Processing.Processors.Transforms -{ - /// - /// Holds the values in an optimized contigous memory region. - /// - internal class WeightsBuffer : IDisposable - { - private readonly Buffer2D dataBuffer; - - /// - /// Initializes a new instance of the class. - /// - /// The to use for allocations. - /// The size of the destination window - /// The radius of the kernel - public WeightsBuffer(MemoryAllocator memoryAllocator, int destinationSize, float kernelRadius) - { - int width = (int)Math.Ceiling(kernelRadius * 2); - this.dataBuffer = memoryAllocator.Allocate2D(width, destinationSize, AllocationOptions.Clean); - this.Weights = new WeightsWindow[destinationSize]; - } - - /// - /// Gets the calculated values. - /// - public WeightsWindow[] Weights { get; } - - /// - /// Disposes instance releasing it's backing buffer. - /// - public void Dispose() - { - this.dataBuffer.Dispose(); - } - - /// - /// Slices a weights value at the given positions. - /// - /// The index in destination buffer - /// The local left index value - /// The local right index value - /// The weights - public WeightsWindow GetWeightsWindow(int destIdx, int leftIdx, int rightIdx) - { - return new WeightsWindow(destIdx, leftIdx, this.dataBuffer, rightIdx - leftIdx + 1); - } - } -} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs new file mode 100644 index 0000000000..b60853a80e --- /dev/null +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -0,0 +1,61 @@ +using System; +using System.IO; +using System.Text; + +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; +using SixLabors.ImageSharp.Processing.Processors.Transforms; +using SixLabors.Primitives; + +using Xunit; +using Xunit.Abstractions; + +namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms +{ + public class KernelMapTests + { + private ITestOutputHelper Output { get; } + + public KernelMapTests(ITestOutputHelper output) + { + this.Output = output; + } + + [Theory] + [InlineData(500, 200, nameof(KnownResamplers.Bicubic))] + [InlineData(50, 40, nameof(KnownResamplers.Bicubic))] + [InlineData(40, 30, nameof(KnownResamplers.Bicubic))] + [InlineData(500, 200, nameof(KnownResamplers.Lanczos8))] + [InlineData(100, 80, nameof(KnownResamplers.Lanczos8))] + [InlineData(100, 10, nameof(KnownResamplers.Lanczos8))] + [InlineData(10, 100, nameof(KnownResamplers.Lanczos8))] + public void PrintKernelMap(int srcSize, int destSize, string resamplerName) + { + var resampler = (IResampler)typeof(KnownResamplers).GetProperty(resamplerName).GetValue(null); + + var kernelMap = KernelMap.Calculate(resampler, destSize, srcSize, Configuration.Default.MemoryAllocator); + + var bld = new StringBuilder(); + + foreach (ResizeKernel window in kernelMap.Kernels) + { + Span span = window.GetSpan(); + for (int i = 0; i < window.Length; i++) + { + float value = span[i]; + bld.Append($"{value,7:F4}"); + bld.Append("| "); + } + + bld.AppendLine(); + } + + string outDir = TestEnvironment.CreateOutputDirectory("." + nameof(this.PrintKernelMap)); + string fileName = $@"{outDir}\{resamplerName}_{srcSize}_{destSize}.MD"; + + File.WriteAllText(fileName, bld.ToString()); + + this.Output.WriteLine(bld.ToString()); + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs index 4a35d63020..f0062d7146 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs @@ -40,43 +40,5 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms }); } - [Theory] - [InlineData(500, 200, nameof(KnownResamplers.Bicubic))] - [InlineData(50, 40, nameof(KnownResamplers.Bicubic))] - [InlineData(40, 30, nameof(KnownResamplers.Bicubic))] - [InlineData(500, 200, nameof(KnownResamplers.Lanczos8))] - [InlineData(100, 80, nameof(KnownResamplers.Lanczos8))] - [InlineData(100, 10, nameof(KnownResamplers.Lanczos8))] - [InlineData(10, 100, nameof(KnownResamplers.Lanczos8))] - public void PrintWeightsData(int srcSize, int destSize, string resamplerName) - { - var size = new Size(srcSize, srcSize); - var resampler = (IResampler) typeof(KnownResamplers).GetProperty(resamplerName).GetValue(null); - var proc = new ResizeProcessor(resampler, destSize, destSize, size); - - WeightsBuffer weights = proc.PrecomputeWeights(Configuration.Default.MemoryAllocator, proc.Width, size.Width); - - var bld = new StringBuilder(); - - foreach (WeightsWindow window in weights.Weights) - { - Span span = window.GetWindowSpan(); - for (int i = 0; i < window.Length; i++) - { - float value = span[i]; - bld.Append($"{value,7:F4}"); - bld.Append("| "); - } - - bld.AppendLine(); - } - - string outDir = TestEnvironment.CreateOutputDirectory("." + nameof(this.PrintWeightsData)); - string fileName = $@"{outDir}\{resamplerName}_{srcSize}_{destSize}.MD"; - - File.WriteAllText(fileName, bld.ToString()); - - this.Output.WriteLine(bld.ToString()); - } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index a84adbe1c6..1e0f86dcb8 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -11,6 +11,7 @@ using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.Primitives; using Xunit; + namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { public class ResizeTests : FileTestBase From 48f8815f5e852d9101f890f8cad3c4045c382544 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 01:25:53 +0200 Subject: [PATCH 155/185] add bulk Premultiply --- .../Common/Extensions/Vector4Extensions.cs | 1 + src/ImageSharp/Common/Helpers/ImageMaths.cs | 23 ++++++++++++++++++ .../Helpers/ImageMathsTests.cs | 19 +++++++++++++++ .../TestUtilities/TestDataGenerator.cs | 24 ++++++++++++++++++- 4 files changed, 66 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs index b88c229c5d..7fb5fd8ee3 100644 --- a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs +++ b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index b3a1b4ba39..a318d1941c 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -2,7 +2,10 @@ // Licensed under the Apache License, Version 2.0. using System; +using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -275,5 +278,25 @@ namespace SixLabors.ImageSharp return GetBoundingRectangle(topLeft, bottomRight); } + + /// + /// Pre-multiply all vectors. + /// "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact. + /// + /// + /// The span of vectors + public static void Premultiply(Span vectors) + { + // TODO: This method can be AVX2 optimized using Vector + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + var s = new Vector4(v.W); + s.W = 1; + v *= s; + } + } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 41e6b65c56..51b407f86a 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -1,6 +1,10 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using System; +using System.Linq; +using System.Numerics; + using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers @@ -35,6 +39,21 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(expected, actual); } + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void Premultiply_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => v.Premultiply()).ToArray(); + + ImageMaths.Premultiply(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + // TODO: We need to test all ImageMaths methods! } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs index 9eb051e7a7..0b1b89cc00 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestDataGenerator.cs @@ -1,4 +1,5 @@ using System; +using System.Numerics; namespace SixLabors.ImageSharp.Tests { @@ -10,7 +11,23 @@ namespace SixLabors.ImageSharp.Tests for (int i = 0; i < length; i++) { - values[i] = (float)rnd.NextDouble() * (maxVal - minVal) + minVal; + values[i] = GetRandomFloat(rnd, minVal, maxVal); + } + + return values; + } + + public static Vector4[] GenerateRandomVectorArray(this Random rnd, int length, float minVal, float maxVal) + { + var values = new Vector4[length]; + + for (int i = 0; i < length; i++) + { + ref Vector4 v = ref values[i]; + v.X = GetRandomFloat(rnd, minVal, maxVal); + v.Y = GetRandomFloat(rnd, minVal, maxVal); + v.Z = GetRandomFloat(rnd, minVal, maxVal); + v.W = GetRandomFloat(rnd, minVal, maxVal); } return values; @@ -28,5 +45,10 @@ namespace SixLabors.ImageSharp.Tests return values; } + + private static float GetRandomFloat(Random rnd, float minVal, float maxVal) + { + return (float)rnd.NextDouble() * (maxVal - minVal) + minVal; + } } } \ No newline at end of file From 08ebbf5ab7a2f867fde7aed19bdfe5a3284d9425 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 01:41:26 +0200 Subject: [PATCH 156/185] separate PreMultiply from Convonution for rows --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 19 +++++++++++++++++++ .../Processors/Transforms/ResizeKernel.cs | 10 +++++----- .../Processors/Transforms/ResizeProcessor.cs | 6 +++--- .../Helpers/ImageMathsTests.cs | 15 +++++++++++++++ 4 files changed, 42 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index a318d1941c..6accad43fc 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -298,5 +298,24 @@ namespace SixLabors.ImageSharp v *= s; } } + + /// + /// Revers + /// + /// + /// The span of vectors + public static void UnPremultiply(Span vectors) + { + // TODO: This method can be AVX2 optimized using Vector + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + var s = new Vector4(1 / v.W); + s.W = 1; + v *= s; + } + } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index f149523fc7..a69ceea5c4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The source row position. /// The weighted sum [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ConvolvePremultipliedRows(Span rowSpan, int sourceX) + public Vector4 ConvolveRows(Span rowSpan, int sourceX) { ref float horizontalValues = ref this.GetStartReference(); int left = this.Left; @@ -91,7 +91,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { float weight = Unsafe.Add(ref horizontalValues, i); Vector4 v = Unsafe.Add(ref vecPtr, i); - result += v.Premultiply() * weight; + result += v * weight; } return result; @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The source row position. /// The weighted sum [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ConvolvePremultipliedExpandedRows(Span rowSpan, int sourceX) + public Vector4 ConvolveExpandRows(Span rowSpan, int sourceX) { ref float horizontalValues = ref this.GetStartReference(); int left = this.Left; @@ -118,10 +118,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { float weight = Unsafe.Add(ref horizontalValues, i); Vector4 v = Unsafe.Add(ref vecPtr, i); - result += v.Premultiply().Expand() * weight; + result += v.Expand() * weight; } - return result.UnPremultiply(); + return result; } /// diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 52ed222cad..2643206b47 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -142,7 +142,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// public bool Compand { get; } - /// protected override Image CreateDestination(Image source, Rectangle sourceRectangle) { @@ -254,6 +253,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span tempRowSpan = tempRowBuffer.Span; PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length); + ImageMaths.Premultiply(tempRowSpan); if (this.Compand) { @@ -261,7 +261,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; Unsafe.Add(ref firstPassRow, x) = - window.ConvolvePremultipliedExpandedRows(tempRowSpan, sourceX); + window.ConvolveExpandRows(tempRowSpan, sourceX).UnPremultiply(); } } else @@ -270,7 +270,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; Unsafe.Add(ref firstPassRow, x) = - window.ConvolvePremultipliedRows(tempRowSpan, sourceX); + window.ConvolveRows(tempRowSpan, sourceX); } } } diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 51b407f86a..3f41a9955e 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -54,6 +54,21 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); } + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void UnPremultiply_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => v.UnPremultiply()).ToArray(); + + ImageMaths.UnPremultiply(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + // TODO: We need to test all ImageMaths methods! } } \ No newline at end of file From e034162b3a8e6f1311e20caf79a12400583a0586 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 02:07:15 +0200 Subject: [PATCH 157/185] use transposed buffer in ResizeProcessor --- .../Processors/Transforms/ResizeKernel.cs | 31 ++----------------- .../Processors/Transforms/ResizeProcessor.cs | 31 +++++++------------ 2 files changed, 14 insertions(+), 48 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index a69ceea5c4..eeb4aef191 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -78,7 +78,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The source row position. /// The weighted sum [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ConvolveRows(Span rowSpan, int sourceX) + public Vector4 Convolve(Span rowSpan, int sourceX) { ref float horizontalValues = ref this.GetStartReference(); int left = this.Left; @@ -105,7 +105,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The source row position. /// The weighted sum [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ConvolveExpandRows(Span rowSpan, int sourceX) + public Vector4 ConvolveExpand(Span rowSpan, int sourceX) { ref float horizontalValues = ref this.GetStartReference(); int left = this.Left; @@ -123,32 +123,5 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return result; } - - /// - /// Computes the sum of vectors in 'firstPassPixels' at a row pointed by 'x', - /// weighted by weight values, pointed by this instance. - /// - /// The buffer of input vectors in row first order - /// The row position - /// The source column position. - /// The weighted sum - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ConvolveColumnsAndUnPremultiply(Buffer2D firstPassPixels, int x, int sourceY) - { - ref float verticalValues = ref this.GetStartReference(); - int left = this.Left; - - // Destination color components - Vector4 result = Vector4.Zero; - - for (int i = 0; i < this.Length; i++) - { - float yw = Unsafe.Add(ref verticalValues, i); - int index = left + i + sourceY; - result += firstPassPixels[x, index] * yw; - } - - return result.UnPremultiply(); - } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 2643206b47..3c13d781e0 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -233,10 +233,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm // First process the columns. Since we are not using multiple threads startY and endY // are the upper and lower bounds of the source rectangle. - // TODO: Using a transposed variant of 'firstPassPixels' could eliminate the need for the WeightsWindow.ComputeWeightedColumnSum() method, and improve speed! - using (Buffer2D firstPassPixels = source.MemoryAllocator.Allocate2D(width, source.Height)) + using (Buffer2D firstPassPixelsTransposed = source.MemoryAllocator.Allocate2D(source.Height, width)) { - firstPassPixels.MemorySource.Clear(); + firstPassPixelsTransposed.MemorySource.Clear(); var processColsRect = new Rectangle(0, 0, source.Width, sourceRectangle.Bottom); @@ -247,8 +246,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { for (int y = rows.Min; y < rows.Max; y++) { - ref Vector4 firstPassRow = - ref MemoryMarshal.GetReference(firstPassPixels.GetRowSpan(y)); Span sourceRow = source.GetPixelRowSpan(y); Span tempRowSpan = tempRowBuffer.Span; @@ -260,8 +257,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = minX; x < maxX; x++) { ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; - Unsafe.Add(ref firstPassRow, x) = - window.ConvolveExpandRows(tempRowSpan, sourceX).UnPremultiply(); + firstPassPixelsTransposed[y, x] = window.ConvolveExpand(tempRowSpan, sourceX).UnPremultiply(); } } else @@ -269,8 +265,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = minX; x < maxX; x++) { ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; - Unsafe.Add(ref firstPassRow, x) = - window.ConvolveRows(tempRowSpan, sourceX); + firstPassPixelsTransposed[y, x] = + window.Convolve(tempRowSpan, sourceX); } } } @@ -294,12 +290,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { for (int x = 0; x < width; x++) { + Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x); + // Destination color components - Vector4 destinationVector = window.ConvolveColumnsAndUnPremultiply( - firstPassPixels, - x, - sourceY); - destinationVector = destinationVector.Compress(); + Vector4 destinationVector = window.Convolve(firstPassColumn, sourceY); + destinationVector = destinationVector.UnPremultiply().Compress(); ref TPixel pixel = ref Unsafe.Add(ref targetRow, x); pixel.PackFromVector4(destinationVector); @@ -309,12 +304,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms { for (int x = 0; x < width; x++) { - // Destination color components - Vector4 destinationVector = window.ConvolveColumnsAndUnPremultiply( - firstPassPixels, - x, - sourceY); + Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x); + // Destination color components + Vector4 destinationVector = window.Convolve(firstPassColumn, sourceY).UnPremultiply(); ref TPixel pixel = ref Unsafe.Add(ref targetRow, x); pixel.PackFromVector4(destinationVector); } From 75ec80a803e4809ebf93bcccfdce6369b962b21c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 02:52:11 +0200 Subject: [PATCH 158/185] better separation + optimized row processing --- .../Common/Extensions/Vector4Extensions.cs | 70 +++++++++++++++++ src/ImageSharp/Common/Helpers/ImageMaths.cs | 39 ---------- .../Processors/Transforms/ResizeProcessor.cs | 14 +++- .../Helpers/ImageMathsTests.cs | 33 -------- .../Helpers/Vector4ExtensionsTests.cs | 76 +++++++++++++++++++ .../Processors/Transforms/ResizeTests.cs | 12 +++ 6 files changed, 168 insertions(+), 76 deletions(-) create mode 100644 tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs diff --git a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs index 7fb5fd8ee3..8dc9c96a06 100644 --- a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs +++ b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs @@ -43,6 +43,42 @@ namespace SixLabors.ImageSharp return unpremultiplied; } + /// + /// Bulk variant of + /// + /// The span of vectors + public static void Premultiply(Span vectors) + { + // TODO: This method can be AVX2 optimized using Vector + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + var s = new Vector4(v.W); + s.W = 1; + v *= s; + } + } + + /// + /// Bulk variant of + /// + /// The span of vectors + public static void UnPremultiply(Span vectors) + { + // TODO: This method can be AVX2 optimized using Vector + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + var s = new Vector4(1 / v.W); + s.W = 1; + v *= s; + } + } + /// /// Compresses a linear color signal to its sRGB equivalent. /// @@ -71,6 +107,40 @@ namespace SixLabors.ImageSharp return new Vector4(Expand(gamma.X), Expand(gamma.Y), Expand(gamma.Z), gamma.W); } + /// + /// Bulk variant of + /// + /// The span of vectors + public static void Compress(Span vectors) + { + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + v.X = Compress(v.X); + v.Y = Compress(v.Y); + v.Z = Compress(v.Z); + } + } + + /// + /// Bulk variant of + /// + /// The span of vectors + public static void Expand(Span vectors) + { + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + v.X = Expand(v.X); + v.Y = Expand(v.Y); + v.Z = Expand(v.Z); + } + } + /// /// Gets the compressed sRGB value from an linear signal. /// diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 6accad43fc..8cd34f5402 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -278,44 +278,5 @@ namespace SixLabors.ImageSharp return GetBoundingRectangle(topLeft, bottomRight); } - - /// - /// Pre-multiply all vectors. - /// "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact. - /// - /// - /// The span of vectors - public static void Premultiply(Span vectors) - { - // TODO: This method can be AVX2 optimized using Vector - ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); - - for (int i = 0; i < vectors.Length; i++) - { - ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - var s = new Vector4(v.W); - s.W = 1; - v *= s; - } - } - - /// - /// Revers - /// - /// - /// The span of vectors - public static void UnPremultiply(Span vectors) - { - // TODO: This method can be AVX2 optimized using Vector - ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); - - for (int i = 0; i < vectors.Length; i++) - { - ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - var s = new Vector4(1 / v.W); - s.W = 1; - v *= s; - } - } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 3c13d781e0..9481be48b9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -229,11 +229,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return; } + int sourceHeight = source.Height; + // Interpolate the image using the calculated weights. // A 2-pass 1D algorithm appears to be faster than splitting a 1-pass 2D algorithm // First process the columns. Since we are not using multiple threads startY and endY // are the upper and lower bounds of the source rectangle. - using (Buffer2D firstPassPixelsTransposed = source.MemoryAllocator.Allocate2D(source.Height, width)) + using (Buffer2D firstPassPixelsTransposed = source.MemoryAllocator.Allocate2D(sourceHeight, width)) { firstPassPixelsTransposed.MemorySource.Clear(); @@ -250,14 +252,18 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span tempRowSpan = tempRowBuffer.Span; PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length); - ImageMaths.Premultiply(tempRowSpan); + Vector4Extensions.Premultiply(tempRowSpan); + + ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; if (this.Compand) { for (int x = minX; x < maxX; x++) { ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; - firstPassPixelsTransposed[y, x] = window.ConvolveExpand(tempRowSpan, sourceX).UnPremultiply(); + + Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = + window.ConvolveExpand(tempRowSpan, sourceX).UnPremultiply(); } } else @@ -265,7 +271,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int x = minX; x < maxX; x++) { ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; - firstPassPixelsTransposed[y, x] = + Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = window.Convolve(tempRowSpan, sourceX); } } diff --git a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs index 3f41a9955e..61f06da9f0 100644 --- a/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/ImageMathsTests.cs @@ -1,10 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Linq; -using System.Numerics; - using Xunit; namespace SixLabors.ImageSharp.Tests.Helpers @@ -39,35 +35,6 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(expected, actual); } - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void Premultiply_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => v.Premultiply()).ToArray(); - - ImageMaths.Premultiply(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } - - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void UnPremultiply_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => v.UnPremultiply()).ToArray(); - - ImageMaths.UnPremultiply(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } // TODO: We need to test all ImageMaths methods! } diff --git a/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs b/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs new file mode 100644 index 0000000000..68f71d88f8 --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs @@ -0,0 +1,76 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Linq; +using System.Numerics; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Helpers +{ + public class Vector4ExtensionsTests + { + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void Premultiply_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => v.Premultiply()).ToArray(); + + Vector4Extensions.Premultiply(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void UnPremultiply_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => v.UnPremultiply()).ToArray(); + + Vector4Extensions.UnPremultiply(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void Expand_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => v.Expand()).ToArray(); + + Vector4Extensions.Expand(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void Compress_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => v.Compress()).ToArray(); + + Vector4Extensions.Compress(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + + + } +} diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index 1e0f86dcb8..c74b40622a 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -144,6 +144,18 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } + [Theory] + [WithFile(TestImages.Png.Kaboom, DefaultPixelType)] + public void Resize_Compand_DoesNotBleedAlphaPixels(TestImageProvider provider) + where TPixel : struct, IPixel + { + using (Image image = provider.GetImage()) + { + image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2, true)); + image.DebugSave(provider); + } + } + [Theory] [WithFile(TestImages.Gif.Giphy, DefaultPixelType)] public void Resize_IsAppliedToAllFrames(TestImageProvider provider) From 3de0b1ad4499d65e146f54eb9e61df38afe268ee Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 11:08:47 +0200 Subject: [PATCH 159/185] WIP better Resize benchmarks --- .../ImageSharp.Benchmarks/Samplers/Resize.cs | 120 +++++++++--------- 1 file changed, 58 insertions(+), 62 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index 86dc13e91e..7e8fac2b05 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -1,7 +1,5 @@ -// -// Copyright (c) James Jackson-South and contributors. +// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -// using System; using System.Drawing; @@ -9,90 +7,88 @@ using System.Drawing.Drawing2D; using BenchmarkDotNet.Attributes; +using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using CoreSize = SixLabors.Primitives.Size; - namespace SixLabors.ImageSharp.Benchmarks { - using System.Threading.Tasks; - - using SixLabors.ImageSharp.Formats.Jpeg; - [Config(typeof(Config.ShortClr))] - public class Resize : BenchmarkBase + public abstract class ResizeBenchmarkBase { - private readonly Configuration configuration = new Configuration(new JpegConfigurationModule()); + protected readonly Configuration Configuration = new Configuration(new JpegConfigurationModule()); + + private Image sourceImage; + + private Bitmap sourceBitmap; + + public const int SourceSize = 2000; - [Params(false, true)] - public bool EnableParallelExecution { get; set; } + public const int DestSize = 400; + + [Params(1/*, 4, 8*/)] + public int MaxDegreeOfParallelism { get; set; } [GlobalSetup] public void Setup() { - this.configuration.MaxDegreeOfParallelism = - this.EnableParallelExecution ? Environment.ProcessorCount : 1; + this.Configuration.MaxDegreeOfParallelism = this.MaxDegreeOfParallelism; + + this.sourceImage = new Image(this.Configuration, SourceSize, SourceSize); + this.sourceBitmap = new Bitmap(SourceSize, SourceSize); + } + + [GlobalCleanup] + public void Cleanup() + { + this.sourceImage.Dispose(); + this.sourceBitmap.Dispose(); } - [Benchmark(Baseline = true, Description = "System.Drawing Resize")] - public Size ResizeSystemDrawing() + [Benchmark(Baseline = true)] + public int SystemDrawing() { - using (Bitmap source = new Bitmap(2000, 2000)) + using (var destination = new Bitmap(DestSize, DestSize)) { - using (Bitmap destination = new Bitmap(400, 400)) + using (var graphics = Graphics.FromImage(destination)) { - using (Graphics graphics = Graphics.FromImage(destination)) - { - graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; - graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; - graphics.CompositingQuality = CompositingQuality.HighQuality; - graphics.DrawImage(source, 0, 0, 400, 400); - } - - return destination.Size; + graphics.InterpolationMode = InterpolationMode.HighQualityBicubic; + graphics.PixelOffsetMode = PixelOffsetMode.HighQuality; + graphics.CompositingQuality = CompositingQuality.HighQuality; + graphics.DrawImage(this.sourceBitmap, 0, 0, DestSize, DestSize); } + + return destination.Width; } } - [Benchmark(Description = "ImageSharp Resize")] - public CoreSize ResizeCore() + [Benchmark] + public int ImageSharp() { - using (var image = new Image(this.configuration, 2000, 2000)) + using (Image clone = this.sourceImage.Clone(this.ExecuteResizeOperation)) { - image.Mutate(x => x.Resize(400, 400)); - return new CoreSize(image.Width, image.Height); + //Console.WriteLine($"{this.sourceImage.Width} -> {clone.Width} ?"); + return clone.Width; } } - //[Benchmark(Description = "ImageSharp Vector Resize")] - //public CoreSize ResizeCoreVector() - //{ - // using (Image image = new Image(2000, 2000)) - // { - // image.Resize(400, 400); - // return new CoreSize(image.Width, image.Height); - // } - //} - - //[Benchmark(Description = "ImageSharp Compand Resize")] - //public CoreSize ResizeCoreCompand() - //{ - // using (Image image = new Image(2000, 2000)) - // { - // image.Resize(400, 400, true); - // return new CoreSize(image.Width, image.Height); - // } - //} - - //[Benchmark(Description = "ImageSharp Vector Compand Resize")] - //public CoreSize ResizeCoreVectorCompand() - //{ - // using (Image image = new Image(2000, 2000)) - // { - // image.Resize(400, 400, true); - // return new CoreSize(image.Width, image.Height); - // } - //} + protected abstract void ExecuteResizeOperation(IImageProcessingContext ctx); + } + + public class Resize_Bicubic : ResizeBenchmarkBase + { + protected override void ExecuteResizeOperation(IImageProcessingContext ctx) + { + //Console.WriteLine("wtf?"); + ctx.Resize(DestSize, DestSize, KnownResamplers.Bicubic); + } + } + + public class Resize_BicubicCompand : ResizeBenchmarkBase + { + protected override void ExecuteResizeOperation(IImageProcessingContext ctx) + { + ctx.Resize(DestSize, DestSize, KnownResamplers.Bicubic, true); + } } } From fc7eee84007e4265bebd06e3a239f86b2e42b53c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 12:02:17 +0200 Subject: [PATCH 160/185] better profiler output for ResizeProcessor --- .../Common/Extensions/Vector4Extensions.cs | 12 ++++---- .../Common/Helpers/InliningOptions.cs | 2 +- .../Processors/Transforms/ResizeKernel.cs | 10 +++---- .../ImageSharp.Benchmarks/Samplers/Resize.cs | 4 +-- .../Transforms/ResizeProfilingBenchmarks.cs | 29 ++++++++++--------- 5 files changed, 29 insertions(+), 28 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs index 8dc9c96a06..f9bbdfc040 100644 --- a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs +++ b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp /// /// The to premultiply /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static Vector4 Premultiply(this Vector4 source) { float w = source.W; @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp /// /// The to premultiply /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static Vector4 UnPremultiply(this Vector4 source) { float w = source.W; @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp /// /// The whose signal to compress. /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static Vector4 Compress(this Vector4 linear) { // TODO: Is there a faster way to do this? @@ -100,7 +100,7 @@ namespace SixLabors.ImageSharp /// /// The whose signal to expand. /// The . - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public static Vector4 Expand(this Vector4 gamma) { // TODO: Is there a faster way to do this? @@ -150,7 +150,7 @@ namespace SixLabors.ImageSharp /// /// The . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static float Compress(float signal) { if (signal <= 0.0031308F) @@ -170,7 +170,7 @@ namespace SixLabors.ImageSharp /// /// The . /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] private static float Expand(float signal) { if (signal <= 0.04045F) diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index e1d51da8d4..9356abeb9a 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. // Uncomment this for verbose profiler results: -// #define PROFILING +#define PROFILING using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index eeb4aef191..902f6a1c09 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -44,7 +44,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The local left index /// The span /// The length of the window - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] internal ResizeKernel(int index, int left, Buffer2D buffer, int length) { this.flatStartIndex = index * buffer.Width; @@ -57,7 +57,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Gets a reference to the first item of the window. /// /// The reference to the first item of the window - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public ref float GetStartReference() { Span span = this.buffer.Span; @@ -68,7 +68,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// Gets the span representing the portion of the that this window covers /// /// The - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Span GetSpan() => this.buffer.Span.Slice(this.flatStartIndex, this.Length); /// @@ -77,7 +77,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The input span of vectors /// The source row position. /// The weighted sum - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 Convolve(Span rowSpan, int sourceX) { ref float horizontalValues = ref this.GetStartReference(); @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// The input span of vectors /// The source row position. /// The weighted sum - [MethodImpl(MethodImplOptions.AggressiveInlining)] + [MethodImpl(InliningOptions.ShortMethod)] public Vector4 ConvolveExpand(Span rowSpan, int sourceX) { ref float horizontalValues = ref this.GetStartReference(); diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index 7e8fac2b05..0cea9245ad 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -26,7 +26,7 @@ namespace SixLabors.ImageSharp.Benchmarks public const int DestSize = 400; - [Params(1/*, 4, 8*/)] + [Params(1, 4, 8)] public int MaxDegreeOfParallelism { get; set; } [GlobalSetup] @@ -67,7 +67,6 @@ namespace SixLabors.ImageSharp.Benchmarks { using (Image clone = this.sourceImage.Clone(this.ExecuteResizeOperation)) { - //Console.WriteLine($"{this.sourceImage.Width} -> {clone.Width} ?"); return clone.Width; } } @@ -79,7 +78,6 @@ namespace SixLabors.ImageSharp.Benchmarks { protected override void ExecuteResizeOperation(IImageProcessingContext ctx) { - //Console.WriteLine("wtf?"); ctx.Resize(DestSize, DestSize, KnownResamplers.Bicubic); } } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs index f0062d7146..9dde8c9cf5 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs @@ -1,15 +1,8 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.IO; -using System.Text; - using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing; -using SixLabors.ImageSharp.Processing.Processors.Transforms; - -using SixLabors.Primitives; using Xunit; using Xunit.Abstractions; @@ -18,24 +11,34 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { public class ResizeProfilingBenchmarks : MeasureFixture { + public const string SkipText = +#if true + null; +#else + "Benchmark, enable manually"! +#endif + + private readonly Configuration configuration = Configuration.CreateDefaultInstance(); + public ResizeProfilingBenchmarks(ITestOutputHelper output) : base(output) { + this.configuration.MaxDegreeOfParallelism = 1; } public int ExecutionCount { get; set; } = 50; - - // [Theory] // Benchmark, enable manually! - // [InlineData(100, 100)] - // [InlineData(2000, 2000)] + + [Theory(Skip = SkipText)] + [InlineData(100, 100)] + [InlineData(2000, 2000)] public void ResizeBicubic(int width, int height) { this.Measure(this.ExecutionCount, () => { - using (var image = new Image(width, height)) + using (var image = new Image(this.configuration, width, height)) { - image.Mutate(x => x.Resize(width / 4, height / 4)); + image.Mutate(x => x.Resize(width / 5, height / 5)); } }); } From 86b2bfe10028a62b4281ce939b82caf2bc788cf9 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 20:17:59 +0200 Subject: [PATCH 161/185] Fix ResizeProcessor Compand UnPremultiply bug + tests --- src/ImageSharp/Common/Helpers/ImageMaths.cs | 3 +- .../Processors/Transforms/ResizeProcessor.cs | 2 +- .../Processors/Transforms/ResizeTests.cs | 64 ++++++------------- tests/Images/External | 2 +- 4 files changed, 24 insertions(+), 47 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/ImageMaths.cs b/src/ImageSharp/Common/Helpers/ImageMaths.cs index 8cd34f5402..d672cfd5a9 100644 --- a/src/ImageSharp/Common/Helpers/ImageMaths.cs +++ b/src/ImageSharp/Common/Helpers/ImageMaths.cs @@ -2,9 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Numerics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; using SixLabors.ImageSharp.PixelFormats; using SixLabors.Primitives; @@ -33,6 +31,7 @@ namespace SixLabors.ImageSharp /// /// Determine the Least Common Multiple (LCM) of two numbers. + /// TODO: This method might be useful for building a more compact /// public static int LeastCommonMultiple(int a, int b) { diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 9481be48b9..753863dec9 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -263,7 +263,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = - window.ConvolveExpand(tempRowSpan, sourceX).UnPremultiply(); + window.ConvolveExpand(tempRowSpan, sourceX); } } else diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index c74b40622a..ca43432e72 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -18,8 +18,8 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms { public static readonly string[] CommonTestImages = { TestImages.Png.CalliphoraPartial }; - private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.069F); - + private static readonly ImageComparer ValidatorComparer = ImageComparer.TolerantPercentage(0.07F); + public static readonly TheoryData AllReSamplers = new TheoryData { @@ -65,20 +65,16 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public void Resize_WorksWithAllParallelismLevels(TestImageProvider provider, int maxDegreeOfParallelism) where TPixel : struct, IPixel { - if (maxDegreeOfParallelism >= 0) - { - provider.Configuration.MaxDegreeOfParallelism = maxDegreeOfParallelism; - } + provider.Configuration.MaxDegreeOfParallelism = + maxDegreeOfParallelism > 0 ? maxDegreeOfParallelism : Environment.ProcessorCount; - using (Image image = provider.GetImage()) - { - SizeF newSize = image.Size() * 0.5f; - image.Mutate(x => x.Resize((Size)newSize, false)); - FormattableString details = $"MDP{maxDegreeOfParallelism}"; + FormattableString details = $"MDP{maxDegreeOfParallelism}"; - image.DebugSave(provider, details); - //image.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.005f), provider, details); - } + provider.RunValidatingProcessorTest( + x => x.Resize(x.GetCurrentSize() / 2), + details, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); } [Theory] @@ -100,16 +96,9 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public void Resize_IsNotBoundToSinglePixelType(TestImageProvider provider) where TPixel : struct, IPixel { - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2, true)); - - image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); - } + provider.RunValidatingProcessorTest(x => x.Resize(x.GetCurrentSize() / 2), comparer: ValidatorComparer); } - [Theory] [WithFileCollection(nameof(CommonTestImages), DefaultPixelType)] public void Resize_ThrowsForWrappedMemoryImage(TestImageProvider provider) @@ -130,32 +119,21 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms } } - [Theory] - [WithFile(TestImages.Png.Kaboom, DefaultPixelType)] - public void Resize_DoesNotBleedAlphaPixels(TestImageProvider provider) + [WithFile(TestImages.Png.Kaboom, DefaultPixelType, false)] + [WithFile(TestImages.Png.Kaboom, DefaultPixelType, true)] + public void Resize_DoesNotBleedAlphaPixels(TestImageProvider provider, bool compand) where TPixel : struct, IPixel { - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2)); - image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); - } - } + string details = compand ? "Compand" : ""; - [Theory] - [WithFile(TestImages.Png.Kaboom, DefaultPixelType)] - public void Resize_Compand_DoesNotBleedAlphaPixels(TestImageProvider provider) - where TPixel : struct, IPixel - { - using (Image image = provider.GetImage()) - { - image.Mutate(x => x.Resize(image.Width / 2, image.Height / 2, true)); - image.DebugSave(provider); - } + provider.RunValidatingProcessorTest( + x => x.Resize(x.GetCurrentSize() / 2, compand), + details, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); } - + [Theory] [WithFile(TestImages.Gif.Giphy, DefaultPixelType)] public void Resize_IsAppliedToAllFrames(TestImageProvider provider) diff --git a/tests/Images/External b/tests/Images/External index c0627f384c..03c7fa7582 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit c0627f384c1d3d2f8d914c9578ae31354c35fd2c +Subproject commit 03c7fa7582dea75cea0d49514ccb7e1b6dc9e780 From 1f0d492805c78202cb08ea1ad8804c1994c61f20 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 20:32:47 +0200 Subject: [PATCH 162/185] simplify ResizeProcessor --- .../Processors/Transforms/ResizeKernel.cs | 27 -------- .../Processors/Transforms/ResizeProcessor.cs | 65 +++++++------------ .../Processors/Transforms/ResizeTests.cs | 2 +- 3 files changed, 26 insertions(+), 68 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index 902f6a1c09..ce2e3c92c4 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -96,32 +96,5 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms return result; } - - /// - /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. - /// Applies to all input vectors. - /// - /// The input span of vectors - /// The source row position. - /// The weighted sum - [MethodImpl(InliningOptions.ShortMethod)] - public Vector4 ConvolveExpand(Span rowSpan, int sourceX) - { - ref float horizontalValues = ref this.GetStartReference(); - int left = this.Left; - ref Vector4 vecPtr = ref Unsafe.Add(ref MemoryMarshal.GetReference(rowSpan), left + sourceX); - - // Destination color components - Vector4 result = Vector4.Zero; - - for (int i = 0; i < this.Length; i++) - { - float weight = Unsafe.Add(ref horizontalValues, i); - Vector4 v = Unsafe.Add(ref vecPtr, i); - result += v.Expand() * weight; - } - - return result; - } } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index 753863dec9..0fbd322d91 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -2,13 +2,12 @@ // Licensed under the Apache License, Version 2.0. using System; -using System.Buffers; using System.Collections.Generic; using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Threading.Tasks; + using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; @@ -258,22 +257,14 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms if (this.Compand) { - for (int x = minX; x < maxX; x++) - { - ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; - - Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = - window.ConvolveExpand(tempRowSpan, sourceX); - } + Vector4Extensions.Expand(tempRowSpan); } - else + + for (int x = minX; x < maxX; x++) { - for (int x = minX; x < maxX; x++) - { - ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; - Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = - window.Convolve(tempRowSpan, sourceX); - } + ResizeKernel window = this.horizontalKernelMap.Kernels[x - startX]; + Unsafe.Add(ref firstPassBaseRef, x * sourceHeight) = + window.Convolve(tempRowSpan, sourceX); } } }); @@ -281,43 +272,37 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms var processRowsRect = Rectangle.FromLTRB(0, minY, width, maxY); // Now process the rows. - ParallelHelper.IterateRows( + ParallelHelper.IterateRowsWithTempBuffer( processRowsRect, configuration, - rows => + (rows, tempRowBuffer) => { + Span tempRowSpan = tempRowBuffer.Span; + for (int y = rows.Min; y < rows.Max; y++) { // Ensure offsets are normalized for cropping and padding. ResizeKernel window = this.verticalKernelMap.Kernels[y - startY]; - ref TPixel targetRow = ref MemoryMarshal.GetReference(destination.GetPixelRowSpan(y)); - if (this.Compand) - { - for (int x = 0; x < width; x++) - { - Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x); + ref Vector4 tempRowBase = ref MemoryMarshal.GetReference(tempRowSpan); - // Destination color components - Vector4 destinationVector = window.Convolve(firstPassColumn, sourceY); - destinationVector = destinationVector.UnPremultiply().Compress(); + for (int x = 0; x < width; x++) + { + Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x); - ref TPixel pixel = ref Unsafe.Add(ref targetRow, x); - pixel.PackFromVector4(destinationVector); - } + // Destination color components + Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn, sourceY); } - else + + Vector4Extensions.UnPremultiply(tempRowSpan); + + if (this.Compand) { - for (int x = 0; x < width; x++) - { - Span firstPassColumn = firstPassPixelsTransposed.GetRowSpan(x); - - // Destination color components - Vector4 destinationVector = window.Convolve(firstPassColumn, sourceY).UnPremultiply(); - ref TPixel pixel = ref Unsafe.Add(ref targetRow, x); - pixel.PackFromVector4(destinationVector); - } + Vector4Extensions.Compress(tempRowSpan); } + + Span targetRowSpan = destination.GetPixelRowSpan(y); + PixelOperations.Instance.PackFromVector4(tempRowSpan, targetRowSpan, tempRowSpan.Length); } }); } diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs index ca43432e72..72cb0be423 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeTests.cs @@ -53,7 +53,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms FormattableString details = $"{name}-{ratio.ToString(System.Globalization.CultureInfo.InvariantCulture)}"; image.DebugSave(provider, details); - image.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.005f), provider, details); + image.CompareToReferenceOutput(ImageComparer.TolerantPercentage(0.02f), provider, details); } } From aa93d5c66aeec0e1fb51a87989d436ab1b77b490 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 20:46:31 +0200 Subject: [PATCH 163/185] better Resize benchmarks --- .../ImageSharp.Benchmarks/Samplers/Resize.cs | 21 ++++++++++++------- 1 file changed, 13 insertions(+), 8 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs index 0cea9245ad..f53061d4e1 100644 --- a/tests/ImageSharp.Benchmarks/Samplers/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Samplers/Resize.cs @@ -22,18 +22,13 @@ namespace SixLabors.ImageSharp.Benchmarks private Bitmap sourceBitmap; - public const int SourceSize = 2000; + public const int SourceSize = 3032; public const int DestSize = 400; - [Params(1, 4, 8)] - public int MaxDegreeOfParallelism { get; set; } - [GlobalSetup] public void Setup() { - this.Configuration.MaxDegreeOfParallelism = this.MaxDegreeOfParallelism; - this.sourceImage = new Image(this.Configuration, SourceSize, SourceSize); this.sourceBitmap = new Bitmap(SourceSize, SourceSize); } @@ -62,9 +57,19 @@ namespace SixLabors.ImageSharp.Benchmarks } } - [Benchmark] - public int ImageSharp() + [Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 1")] + public int ImageSharp_P1() => this.RunImageSharpResize(1); + + [Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 4")] + public int ImageSharp_P4() => this.RunImageSharpResize(4); + + [Benchmark(Description = "ImageSharp, MaxDegreeOfParallelism = 8")] + public int ImageSharp_P8() => this.RunImageSharpResize(8); + + protected int RunImageSharpResize(int maxDegreeOfParallelism) { + this.Configuration.MaxDegreeOfParallelism = maxDegreeOfParallelism; + using (Image clone = this.sourceImage.Clone(this.ExecuteResizeOperation)) { return clone.Width; From 6fb25c1f210db2e9a9840acc542cd794b1e03bdf Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 21:35:23 +0200 Subject: [PATCH 164/185] disable profiling-related stuff --- src/ImageSharp/Common/Helpers/InliningOptions.cs | 2 +- .../Processing/Processors/Transforms/KernelMapTests.cs | 2 +- .../Processors/Transforms/ResizeProfilingBenchmarks.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/InliningOptions.cs b/src/ImageSharp/Common/Helpers/InliningOptions.cs index 9356abeb9a..e1d51da8d4 100644 --- a/src/ImageSharp/Common/Helpers/InliningOptions.cs +++ b/src/ImageSharp/Common/Helpers/InliningOptions.cs @@ -2,7 +2,7 @@ // Licensed under the Apache License, Version 2.0. // Uncomment this for verbose profiler results: -#define PROFILING +// #define PROFILING using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs index b60853a80e..1b4b3cf6a3 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/KernelMapTests.cs @@ -21,7 +21,7 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms this.Output = output; } - [Theory] + [Theory(Skip = "TODO: Add asserionts")] [InlineData(500, 200, nameof(KnownResamplers.Bicubic))] [InlineData(50, 40, nameof(KnownResamplers.Bicubic))] [InlineData(40, 30, nameof(KnownResamplers.Bicubic))] diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs index 9dde8c9cf5..e24458d384 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/ResizeProfilingBenchmarks.cs @@ -12,10 +12,10 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Transforms public class ResizeProfilingBenchmarks : MeasureFixture { public const string SkipText = -#if true +#if false null; #else - "Benchmark, enable manually"! + "Benchmark, enable manually!"; #endif private readonly Configuration configuration = Configuration.CreateDefaultInstance(); From 915ab70853af149ac2aea089ccda28a32eeb7abe Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Sun, 7 Oct 2018 21:50:58 +0200 Subject: [PATCH 165/185] Simplify ResizeKernel --- .../Processors/Transforms/ResizeKernel.cs | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs index ce2e3c92c4..cc3c204534 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeKernel.cs @@ -27,11 +27,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// public int Length; - /// - /// The index in the destination buffer - /// - private readonly int flatStartIndex; - /// /// The buffer containing the weights values. /// @@ -47,9 +42,9 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms [MethodImpl(InliningOptions.ShortMethod)] internal ResizeKernel(int index, int left, Buffer2D buffer, int length) { - this.flatStartIndex = index * buffer.Width; + int flatStartIndex = index * buffer.Width; this.Left = left; - this.buffer = buffer.MemorySource.Memory; + this.buffer = buffer.MemorySource.Memory.Slice(flatStartIndex, length); this.Length = length; } @@ -61,7 +56,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms public ref float GetStartReference() { Span span = this.buffer.Span; - return ref span[this.flatStartIndex]; + return ref span[0]; } /// @@ -69,7 +64,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The [MethodImpl(InliningOptions.ShortMethod)] - public Span GetSpan() => this.buffer.Span.Slice(this.flatStartIndex, this.Length); + public Span GetSpan() => this.buffer.Span; /// /// Computes the sum of vectors in 'rowSpan' weighted by weight values, pointed by this instance. From d22dfcdf077c3e444365d67f7b59bf476180421a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 7 Oct 2018 22:16:44 +0100 Subject: [PATCH 166/185] Add some Cmyk tests --- .../CmykAndCieLchConversionTests.cs | 78 ++++++++++++++++++ .../CmykAndCieLuvConversionTests.cs | 79 +++++++++++++++++++ .../CmykAndCieXyyConversionTests.cs | 79 +++++++++++++++++++ .../CmykAndCieXyzConversionTests.cs | 79 +++++++++++++++++++ .../Conversion/CmykAndHslConversionTests.cs | 79 +++++++++++++++++++ .../Conversion/CmykAndHsvConversionTests.cs | 79 +++++++++++++++++++ .../CmykAndHunterLabConversionTests.cs | 79 +++++++++++++++++++ .../Conversion/CmykAndYCbCrConversionTests.cs | 2 +- 8 files changed, 553 insertions(+), 1 deletion(-) create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs create mode 100644 tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs new file mode 100644 index 0000000000..4a0c88c841 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLchConversionTests.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CmykAndCieLchConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.85025, 64.77041, 118.2425)] + public void Convert_Cmyk_to_CieLch(float c, float m, float y, float k, float l, float c2, float h) + { + // Arrange + var input = new Cmyk(c, m, y, k); + var expected = new CieLch(l, c2, h); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLch[5]; + + // Act + var actual = Converter.ToCieLch(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(100, 3.81656E-05, 218.6598, 0, 1.192093E-07, 0, 5.960464E-08)] + [InlineData(62.85025, 64.77041, 118.2425, 0.286581, 0, 0.7975187, 0.34983)] + public void Convert_CieLch_to_Cmyk(float l, float c2, float h, float c, float m, float y, float k) + { + // Arrange + var input = new CieLch(l, c2, h); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new CieLch[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs new file mode 100644 index 0000000000..2131ba630b --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieLuvConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CmykAndCieLuvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 100, -1.937151E-05, 0)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 62.66017, -24.01712, 68.29556)] + public void Convert_Cmyk_to_CieLuv(float c, float m, float y, float k, float l, float u, float v) + { + // Arrange + var input = new Cmyk(c, m, y, k); + var expected = new CieLuv(l, u, v); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieLuv[5]; + + // Act + var actual = Converter.ToCieLuv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(100, -1.937151E-05, 0, 3.576279E-07, 0, 0, 5.960464E-08)] + [InlineData(62.66017, -24.01712, 68.29556, 0.2865804, 0, 0.7975189, 0.3498302)] + public void Convert_CieLuv_to_Cmyk(float l, float u, float v, float c, float m, float y, float k) + { + // Arrange + var input = new CieLuv(l, u, v); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new CieLuv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs new file mode 100644 index 0000000000..ac93aaf25b --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyyConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CmykAndCieXyyConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0.3127266, 0.3290231, 1)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 0.3628971, 0.5289949, 0.3118104)] + public void Convert_Cmyk_to_CieXyy(float c, float m, float y, float k, float x, float y2, float yl) + { + // Arrange + var input = new Cmyk(c, m, y, k); + var expected = new CieXyy(x, y2, yl); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyy[5]; + + // Act + var actual = Converter.ToCieXyy(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0.3127266, 0.3290231, 1, 0, 0, 0, 5.960464E-08)] + [InlineData(0.3628971, 0.5289949, 0.3118104, 0.2865805, 0, 0.7975187, 0.3498302)] + public void Convert_CieXyy_to_Cmyk(float x, float y2, float yl, float c, float m, float y, float k) + { + // Arrange + var input = new CieXyy(x, y2, yl); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new CieXyy[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs new file mode 100644 index 0000000000..cbb8f7dc4e --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndCieXyzConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CmykAndCieXyzConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0.9504699, 1, 1.08883)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 0.2139058, 0.3118104, 0.0637231)] + public void Convert_Cmyk_to_CieXyz(float c, float m, float y, float k, float x, float y2, float z) + { + // Arrange + var input = new Cmyk(c, m, y, k); + var expected = new CieXyz(x, y2, z); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new CieXyz[5]; + + // Act + var actual = Converter.ToCieXyz(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0.9504699, 1, 1.08883, 1.192093E-07, 0, 0, 5.960464E-08)] + [InlineData(0.2139058, 0.3118104, 0.0637231, 0.2865805, 0, 0.7975187, 0.3498302)] + public void Convert_CieXyz_to_Cmyk(float x, float y2, float z, float c, float m, float y, float k) + { + // Arrange + var input = new CieXyz(x, y2, z); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new CieXyz[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs new file mode 100644 index 0000000000..1c9ad170d3 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHslConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CmykAndHslConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0, 1)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 81.56041, 0.6632275, 0.3909085)] + public void Convert_Cmyk_to_Hsl(float c, float m, float y, float k, float h, float s, float l) + { + // Arrange + var input = new Cmyk(c, m, y, k); + var expected = new Hsl(h, s, l); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsl[5]; + + // Act + var actual = Converter.ToHsl(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 1, 0, 0, 0, 0)] + [InlineData(81.56041, 0.6632275, 0.3909085, 0.2865805, 0, 0.7975187, 0.3498302)] + public void Convert_Hsl_to_Cmyk(float h, float s, float l, float c, float m, float y, float k) + { + // Arrange + var input = new Hsl(h, s, l); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new Hsl[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs new file mode 100644 index 0000000000..6fd1ba88ec --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHsvConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CmykAndHsvConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 0, 0, 1)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 81.56041, 0.7975187, 0.6501698)] + public void Convert_Cmyk_to_Hsv(float c, float m, float y, float k, float h, float s, float v) + { + // Arrange + var input = new Cmyk(c, m, y, k); + var expected = new Hsv(h, s, v); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new Hsv[5]; + + // Act + var actual = Converter.ToHsv(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 1, 0, 0, 0, 0)] + [InlineData(81.56041, 0.7975187, 0.6501698, 0.2865805, 0, 0.7975187, 0.3498302)] + public void Convert_Hsv_to_Cmyk(float h, float s, float v, float c, float m, float y, float k) + { + // Arrange + var input = new Hsv(h, s, v); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new Hsv[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs new file mode 100644 index 0000000000..e92ac2e528 --- /dev/null +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndHunterLabConversionTests.cs @@ -0,0 +1,79 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using SixLabors.ImageSharp.ColorSpaces; +using SixLabors.ImageSharp.ColorSpaces.Conversion; +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +{ + /// + /// Tests - conversions. + /// + public class CmykAndHunterLabConversionTests + { + private static readonly ApproximateColorSpaceComparer ColorSpaceComparer = new ApproximateColorSpaceComparer(.0002F); + private static readonly ColorSpaceConverter Converter = new ColorSpaceConverter(); + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(0, 0, 0, 0, 99.99999, 0, -1.66893E-05)] + [InlineData(0.360555, 0.1036901, 0.818514, 0.274615, 55.66742, -27.21679, 31.73834)] + public void Convert_Cmyk_to_HunterLab(float c, float m, float y, float k, float l, float a, float b) + { + // Arrange + var input = new Cmyk(c, m, y, k); + var expected = new HunterLab(l, a, b); + + Span inputSpan = new Cmyk[5]; + inputSpan.Fill(input); + + Span actualSpan = new HunterLab[5]; + + // Act + var actual = Converter.ToHunterLab(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + + /// + /// Tests conversion from to . + /// + [Theory] + [InlineData(99.99999, 0, -1.66893E-05, 1.192093E-07, 1.192093E-07, 0, 5.960464E-08)] + [InlineData(55.66742, -27.21679, 31.73834, 0.2865806, 0, 0.7975186, 0.3498301)] + public void Convert_HunterLab_to_Cmyk(float l, float a, float b, float c, float m, float y, float k) + { + // Arrange + var input = new HunterLab(l, a, b); + var expected = new Cmyk(c, m, y, k); + + Span inputSpan = new HunterLab[5]; + inputSpan.Fill(input); + + Span actualSpan = new Cmyk[5]; + + // Act + var actual = Converter.ToCmyk(input); + Converter.Convert(inputSpan, actualSpan, actualSpan.Length); + + // Assert + Assert.Equal(expected, actual, ColorSpaceComparer); + + for (int i = 0; i < actualSpan.Length; i++) + { + Assert.Equal(expected, actualSpan[i], ColorSpaceComparer); + } + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs index 8c45127e3e..575122661a 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CmykAndYCbCrConversionTests.cs @@ -9,7 +9,7 @@ using Xunit; namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion { /// - /// Tests - conversions. + /// Tests - conversions. /// public class CmykAndYCbCrConversionTests { From f6f093eef25d398deef25c46cc06815de55ed9bd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 10 Oct 2018 13:06:47 +0100 Subject: [PATCH 167/185] Replace ICompanding with static methods. --- .../Conversion/ColorSpaceConverter.CieXyz.cs | 2 +- .../Conversion/ColorSpaceConverter.cs | 2 +- .../Conversion/ColorSpaceConverterOptions.cs | 2 +- .../ColorSpaces/Conversion/ICompanding.cs | 35 -------- .../CIeLchToCieLabConverter.cs | 0 .../CieLabToCieLchConverter.cs | 0 .../CieLabToCieXyzConverter.cs | 0 .../CieLchuvToCieLuvConverter.cs | 0 .../CieLuvToCieLchuvConverter.cs | 0 .../CieLuvToCieXyzConverter.cs | 0 .../CieXyzAndCieXyyConverter.cs | 0 .../CieXyzAndHunterLabConverterBase.cs | 0 .../{ => Converters}/CieXyzAndLmsConverter.cs | 0 .../CieXyzToCieLabConverter.cs | 0 .../CieXyzToCieLuvConverter.cs | 0 .../CieXyzToHunterLabConverter.cs | 0 .../CieXyzToLinearRgbConverter.cs | 4 +- .../{ => Converters}/CmykAndRgbConverter.cs | 0 .../{ => Converters}/HslAndRgbConverter.cs | 0 .../{ => Converters}/HsvAndRgbConverter.cs | 0 .../HunterLabToCieXyzConverter.cs | 0 .../LinearRgbAndCieXyzConverterBase.cs | 2 +- .../LinearRgbToCieXyzConverter.cs | 4 +- .../LinearRgbToRgbConverter.cs | 6 +- .../RgbToLinearRgbConverter.cs | 6 +- .../{ => Converters}/YCbCrAndRgbConverter.cs | 0 .../Implementation/GammaCompanding.cs | 37 -------- .../Conversion/Implementation/LCompanding.cs | 33 ------- .../RGBPrimariesChromaticityCoordinates.cs | 2 +- .../Implementation/Rec709Companding.cs | 27 ------ .../Implementation/RgbWorkingSpace.cs | 90 ------------------- .../Implementation/SRgbCompanding.cs | 33 ------- .../WorkingSpaces/GammaCompanding.cs | 36 ++++++++ .../WorkingSpaces/GammaWorkingSpace.cs | 65 ++++++++++++++ .../WorkingSpaces/LCompanding.cs | 37 ++++++++ .../WorkingSpaces/LWorkingSpace.cs | 31 +++++++ .../{ => WorkingSpaces}/Rec2020Companding.cs | 18 ++-- .../WorkingSpaces/Rec2020WorkingSpace.cs | 31 +++++++ .../WorkingSpaces/Rec709Companding.cs | 35 ++++++++ .../WorkingSpaces/Rec709WorkingSpace.cs | 31 +++++++ .../WorkingSpaces/RgbWorkingSpaceBase.cs | 83 +++++++++++++++++ .../WorkingSpaces/SRgbCompanding.cs | 35 ++++++++ .../WorkingSpaces/SRgbWorkingSpace.cs | 31 +++++++ src/ImageSharp/ColorSpaces/LinearRgb.cs | 10 +-- src/ImageSharp/ColorSpaces/Rgb.cs | 10 +-- .../ColorSpaces/RgbWorkingSpaces.cs | 38 ++++---- .../ApproximateColorspaceComparer.cs | 21 +++-- .../Colorspaces/Conversion/CompandingTests.cs | 31 +++++-- .../TestUtilities/ApproximateFloatComparer.cs | 25 ++---- 49 files changed, 518 insertions(+), 335 deletions(-) delete mode 100644 src/ImageSharp/ColorSpaces/Conversion/ICompanding.cs rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CIeLchToCieLabConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieLabToCieLchConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieLabToCieXyzConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieLchuvToCieLuvConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieLuvToCieLchuvConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieLuvToCieXyzConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieXyzAndCieXyyConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieXyzAndHunterLabConverterBase.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieXyzAndLmsConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieXyzToCieLabConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieXyzToCieLuvConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieXyzToHunterLabConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CieXyzToLinearRgbConverter.cs (92%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/CmykAndRgbConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/HslAndRgbConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/HsvAndRgbConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/HunterLabToCieXyzConverter.cs (100%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/LinearRgbAndCieXyzConverterBase.cs (99%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/LinearRgbToCieXyzConverter.cs (93%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/LinearRgbToRgbConverter.cs (80%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/RgbToLinearRgbConverter.cs (80%) rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => Converters}/YCbCrAndRgbConverter.cs (100%) delete mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs delete mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs delete mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs delete mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs delete mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaCompanding.cs create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LCompanding.cs create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs rename src/ImageSharp/ColorSpaces/Conversion/Implementation/{ => WorkingSpaces}/Rec2020Companding.cs (52%) create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709Companding.cs create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpaceBase.cs create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs create mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs index 5d110552a4..8963ad495a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.CieXyz.cs @@ -470,7 +470,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// /// The source working space /// The - private LinearRgbToCieXyzConverter GetLinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace) + private LinearRgbToCieXyzConverter GetLinearRgbToCieXyzConverter(RgbWorkingSpaceBase workingSpace) { if (this.linearRgbToCieXyzConverter?.SourceWorkingSpace.Equals(workingSpace) == true) { diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs index bcbd64c77a..fe6a57f7ac 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverter.cs @@ -18,7 +18,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion private readonly CieXyz targetLuvWhitePoint; private readonly CieXyz targetLabWhitePoint; private readonly CieXyz targetHunterLabWhitePoint; - private readonly RgbWorkingSpace targetRgbWorkingSpace; + private readonly RgbWorkingSpaceBase targetRgbWorkingSpace; private readonly IChromaticAdaptation chromaticAdaptation; private readonly bool performChromaticAdaptation; private readonly CieXyzAndLmsConverter cieXyzAndLmsConverter; diff --git a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs index 65fe799949..fcd031e263 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/ColorSpaceConverterOptions.cs @@ -40,7 +40,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion /// Gets or sets the target working space used *when creating* RGB colors. (RGB colors on the input already contain the working space information) /// Defaults to: . /// - public RgbWorkingSpace TargetRgbWorkingSpace { get; set; } = Rgb.DefaultWorkingSpace; + public RgbWorkingSpaceBase TargetRgbWorkingSpace { get; set; } = Rgb.DefaultWorkingSpace; /// /// Gets or sets the chromatic adaptation method used. When null, no adaptation will be performed. diff --git a/src/ImageSharp/ColorSpaces/Conversion/ICompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/ICompanding.cs deleted file mode 100644 index 55a7569ffa..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/ICompanding.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation -{ - /// - /// Pair of companding functions for . - /// Used for conversion to and backwards. - /// See also: - /// - public interface ICompanding - { - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// - /// For more info see: - /// - /// - /// The channel value - /// The linear channel value - float Expand(float channel); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent (depends on the RGB color system). - /// - /// - /// For more info see: - /// - /// - /// The channel value - /// The nonlinear channel value - float Compress(float channel); - } -} diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CIeLchToCieLabConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CIeLchToCieLabConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieLchConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieLchConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLabToCieXyzConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLabToCieXyzConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLchuvToCieLuvConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLchuvToCieLuvConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieLchuvConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieLchuvConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieLuvToCieXyzConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieLuvToCieXyzConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndCieXyyConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndCieXyyConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndHunterLabConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndHunterLabConverterBase.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndHunterLabConverterBase.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzAndLmsConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzAndLmsConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLabConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLabConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToCieLuvConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToCieLuvConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToHunterLabConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToHunterLabConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs similarity index 92% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs index 9ccea497b4..3812cdbdd8 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CieXyzToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CieXyzToLinearRgbConverter.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Initializes a new instance of the class. /// /// The target working space. - public CieXyzToLinearRgbConverter(RgbWorkingSpace workingSpace) + public CieXyzToLinearRgbConverter(RgbWorkingSpaceBase workingSpace) { this.TargetWorkingSpace = workingSpace; this.conversionMatrix = GetRgbToCieXyzMatrix(workingSpace); @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Gets the target working space /// - public RgbWorkingSpace TargetWorkingSpace { get; } + public RgbWorkingSpaceBase TargetWorkingSpace { get; } /// /// Performs the conversion from the input to an instance of type. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/CmykAndRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/CmykAndRgbConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/HslAndRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HslAndRgbConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/HsvAndRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HsvAndRgbConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/HunterLabToCieXyzConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/HunterLabToCieXyzConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs similarity index 99% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs index bdf451cd3c..a93773262c 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbAndCieXyzConverterBase.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbAndCieXyzConverterBase.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// The Rgb working space. /// The based on the chromaticity and working space. - public static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpace workingSpace) + public static Matrix4x4 GetRgbToCieXyzMatrix(RgbWorkingSpaceBase workingSpace) { DebugGuard.NotNull(workingSpace, nameof(workingSpace)); RgbPrimariesChromaticityCoordinates chromaticity = workingSpace.ChromaticityCoordinates; diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs similarity index 93% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs index 21a96071af..1030ac9819 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToCieXyzConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToCieXyzConverter.cs @@ -25,7 +25,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// Initializes a new instance of the class. /// /// The target working space. - public LinearRgbToCieXyzConverter(RgbWorkingSpace workingSpace) + public LinearRgbToCieXyzConverter(RgbWorkingSpaceBase workingSpace) { this.SourceWorkingSpace = workingSpace; this.conversionMatrix = GetRgbToCieXyzMatrix(workingSpace); @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// Gets the source working space /// - public RgbWorkingSpace SourceWorkingSpace { get; } + public RgbWorkingSpaceBase SourceWorkingSpace { get; } /// /// Performs the conversion from the input to an instance of type. diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs similarity index 80% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs index ad3ed88ef7..1cc055bee2 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LinearRgbToRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/LinearRgbToRgbConverter.cs @@ -19,9 +19,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public Rgb Convert(in LinearRgb input) { var vector = input.ToVector3(); - vector.X = input.WorkingSpace.Companding.Compress(vector.X); - vector.Y = input.WorkingSpace.Companding.Compress(vector.Y); - vector.Z = input.WorkingSpace.Companding.Compress(vector.Z); + vector.X = input.WorkingSpace.Compress(vector.X); + vector.Y = input.WorkingSpace.Compress(vector.Y); + vector.Z = input.WorkingSpace.Compress(vector.Z); return new Rgb(vector, input.WorkingSpace); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs similarity index 80% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs index 20e2d240a2..03912a421e 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbToLinearRgbConverter.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/RgbToLinearRgbConverter.cs @@ -19,9 +19,9 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation public LinearRgb Convert(in Rgb input) { var vector = input.ToVector3(); - vector.X = input.WorkingSpace.Companding.Expand(vector.X); - vector.Y = input.WorkingSpace.Companding.Expand(vector.Y); - vector.Z = input.WorkingSpace.Companding.Expand(vector.Z); + vector.X = input.WorkingSpace.Expand(vector.X); + vector.Y = input.WorkingSpace.Expand(vector.Y); + vector.Z = input.WorkingSpace.Expand(vector.Z); return new LinearRgb(vector, input.WorkingSpace); } diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs similarity index 100% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/YCbCrAndRgbConverter.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/Converters/YCbCrAndRgbConverter.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs deleted file mode 100644 index 92751e4201..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/GammaCompanding.cs +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation -{ - /// - /// Implements gamma companding - /// - /// - /// - /// - /// - public sealed class GammaCompanding : ICompanding - { - /// - /// Initializes a new instance of the class. - /// - /// The gamma value. - public GammaCompanding(float gamma) => this.Gamma = gamma; - - /// - /// Gets the gamma value - /// - public float Gamma { get; } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public float Expand(float channel) => MathF.Pow(channel, this.Gamma); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public float Compress(float channel) => MathF.Pow(channel, 1 / this.Gamma); - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs deleted file mode 100644 index 085230fbde..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/LCompanding.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation -{ - /// - /// Implements L* companding - /// - /// - /// For more info see: - /// - /// - /// - public sealed class LCompanding : ICompanding - { - /// - [MethodImpl(InliningOptions.ShortMethod)] - public float Expand(float channel) - => channel <= 0.08 ? 100 * channel / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public float Compress(float channel) - { - return channel <= CieConstants.Epsilon - ? channel * CieConstants.Kappa / 100F - : MathF.Pow(1.16F * channel, 0.3333333F) - 0.16F; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs index 14c4d6d777..68b4d95fc6 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RGBPrimariesChromaticityCoordinates.cs @@ -7,7 +7,7 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { /// /// Represents the chromaticity coordinates of RGB primaries. - /// One of the specifiers of . + /// One of the specifiers of . /// public readonly struct RgbPrimariesChromaticityCoordinates : IEquatable { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs deleted file mode 100644 index 77f51e4955..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec709Companding.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation -{ - /// - /// Implements the Rec. 709 companding function - /// - /// - /// http://en.wikipedia.org/wiki/Rec._709 - /// - public sealed class Rec709Companding : ICompanding - { - /// - [MethodImpl(InliningOptions.ShortMethod)] - public float Expand(float channel) - => channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, 2.222222F); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public float Compress(float channel) - => channel < 0.018F ? 4500F * channel : (1.099F * channel) - 0.099F; - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs deleted file mode 100644 index 7e1135b2ed..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/RgbWorkingSpace.cs +++ /dev/null @@ -1,90 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation -{ - /// - /// Trivial implementation of - /// - public class RgbWorkingSpace : IEquatable - { - /// - /// Initializes a new instance of the class. - /// - /// The reference white point. - /// The function pair for converting to and back. - /// The chromaticity of the rgb primaries. - public RgbWorkingSpace(CieXyz referenceWhite, ICompanding companding, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) - { - this.WhitePoint = referenceWhite; - this.Companding = companding; - this.ChromaticityCoordinates = chromaticityCoordinates; - } - - /// - /// Gets the reference white point - /// - public CieXyz WhitePoint { get; } - - /// - /// Gets the function pair for converting to and back. - /// - public ICompanding Companding { get; } - - /// - /// Gets the chromaticity of the rgb primaries. - /// - public RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; } - - /// - /// Compares two objects for equality. - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is equal to the parameter; otherwise, false. - /// - public static bool operator ==(RgbWorkingSpace left, RgbWorkingSpace right) - { - return Equals(left, right); - } - - /// - /// Compares two objects for inequality - /// - /// The on the left side of the operand. - /// The on the right side of the operand. - /// - /// True if the current left is unequal to the parameter; otherwise, false. - /// - public static bool operator !=(RgbWorkingSpace left, RgbWorkingSpace right) - { - return !Equals(left, right); - } - - /// - public override bool Equals(object obj) - { - return obj is RgbWorkingSpace other && this.Equals(other); - } - - /// - public bool Equals(RgbWorkingSpace other) - { - // Object.Equals for ICompanding compares the reference only. - return this.WhitePoint.Equals(other.WhitePoint) - && this.ChromaticityCoordinates.Equals(other.ChromaticityCoordinates) - && Equals(this.Companding, other.Companding); - } - - /// - public override int GetHashCode() - { - int hash = this.WhitePoint.GetHashCode(); - hash = HashHelpers.Combine(hash, this.ChromaticityCoordinates.GetHashCode()); - return HashHelpers.Combine(hash, this.Companding?.GetHashCode() ?? 0); - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs deleted file mode 100644 index 98938e6560..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/SRgbCompanding.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation -{ - /// - /// Implements sRGB companding - /// - /// - /// For more info see: - /// - /// - /// - public sealed class SRgbCompanding : ICompanding - { - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Expand(float channel) - { - return channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); - } - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public float Compress(float channel) - { - return channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaCompanding.cs new file mode 100644 index 0000000000..d9babc7ef2 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaCompanding.cs @@ -0,0 +1,36 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// Implements gamma companding + /// + /// + /// + /// + /// + public static class GammaCompanding + { + /// + /// Expands a companded channel to its linear equivalent with respect to the energy. + /// + /// The channel value. + /// The gamma value. + /// The representing the linear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Expand(float channel, float gamma) => MathF.Pow(channel, gamma); + + /// + /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. + /// + /// The channel value. + /// The gamma value. + /// The representing the nonlinear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Compress(float channel, float gamma) => MathF.Pow(channel, 1 / gamma); + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs new file mode 100644 index 0000000000..6d8b25e9db --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs @@ -0,0 +1,65 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// The gamma working space. + /// + public class GammaWorkingSpace : RgbWorkingSpaceBase + { + /// + /// Initializes a new instance of the class. + /// + /// The gamma value. + /// The reference white point. + /// The chromaticity of the rgb primaries. + public GammaWorkingSpace(float gamma, CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) + : base(referenceWhite, chromaticityCoordinates) => this.Gamma = gamma; + + /// + /// Gets the gamma value. + /// + public float Gamma { get; } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Compress(float channel) => GammaCompanding.Compress(channel, this.Gamma); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Expand(float channel) => GammaCompanding.Expand(channel, this.Gamma); + + /// + public override bool Equals(object obj) + { + if (obj is null) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj is GammaWorkingSpace other) + { + return this.Gamma.Equals(other.Gamma) + && this.WhitePoint.Equals(other.WhitePoint) + && this.ChromaticityCoordinates.Equals(other.ChromaticityCoordinates); + } + + return false; + } + + /// + public override int GetHashCode() + { + int hash = base.GetHashCode(); + return HashHelpers.Combine(hash, this.Gamma.GetHashCode()); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LCompanding.cs new file mode 100644 index 0000000000..ebe7ebe938 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LCompanding.cs @@ -0,0 +1,37 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// Implements L* companding + /// + /// + /// For more info see: + /// + /// + /// + public static class LCompanding + { + /// + /// Expands a companded channel to its linear equivalent with respect to the energy. + /// + /// The channel value. + /// The representing the linear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Expand(float channel) + => channel <= 0.08 ? 100 * channel / CieConstants.Kappa : ImageMaths.Pow3((channel + 0.16F) / 1.16F); + + /// + /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. + /// + /// The channel value + /// The representing the nonlinear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Compress(float channel) + => channel <= CieConstants.Epsilon ? channel * CieConstants.Kappa / 100F : MathF.Pow(1.16F * channel, 0.3333333F) - 0.16F; + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs new file mode 100644 index 0000000000..cbc4be5967 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// L* working space. + /// + public sealed class LWorkingSpace : RgbWorkingSpaceBase + { + /// + /// Initializes a new instance of the class. + /// + /// The reference white point. + /// The chromaticity of the rgb primaries. + public LWorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) + : base(referenceWhite, chromaticityCoordinates) + { + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Compress(float channel) => LCompanding.Compress(channel); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Expand(float channel) => LCompanding.Expand(channel); + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020Companding.cs similarity index 52% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs rename to src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020Companding.cs index d541c3d972..ba77e78f0b 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/Rec2020Companding.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020Companding.cs @@ -13,16 +13,24 @@ namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation /// /// For 10-bits, companding is identical to /// - public sealed class Rec2020Companding : ICompanding + public static class Rec2020Companding { - /// + /// + /// Expands a companded channel to its linear equivalent with respect to the energy. + /// + /// The channel value. + /// The representing the linear channel value. [MethodImpl(InliningOptions.ShortMethod)] - public float Expand(float channel) + public static float Expand(float channel) => channel < 0.08145F ? channel / 4.5F : MathF.Pow((channel + 0.0993F) / 1.0993F, 2.222222F); - /// + /// + /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. + /// + /// The channel value. + /// The representing the nonlinear channel value. [MethodImpl(InliningOptions.ShortMethod)] - public float Compress(float channel) + public static float Compress(float channel) => channel < 0.0181F ? 4500F * channel : (1.0993F * channel) - 0.0993F; } } \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs new file mode 100644 index 0000000000..11f1f84016 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. + /// + public sealed class Rec2020WorkingSpace : RgbWorkingSpaceBase + { + /// + /// Initializes a new instance of the class. + /// + /// The reference white point. + /// The chromaticity of the rgb primaries. + public Rec2020WorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) + : base(referenceWhite, chromaticityCoordinates) + { + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Compress(float channel) => Rec2020Companding.Compress(channel); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Expand(float channel) => Rec2020Companding.Expand(channel); + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709Companding.cs new file mode 100644 index 0000000000..e281339a61 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709Companding.cs @@ -0,0 +1,35 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// Implements the Rec. 709 companding function. + /// + /// + /// http://en.wikipedia.org/wiki/Rec._709 + /// + public static class Rec709Companding + { + /// + /// Expands a companded channel to its linear equivalent with respect to the energy. + /// + /// The channel value. + /// The representing the linear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Expand(float channel) + => channel < 0.081F ? channel / 4.5F : MathF.Pow((channel + 0.099F) / 1.099F, 2.222222F); + + /// + /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. + /// + /// The channel value. + /// The representing the nonlinear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Compress(float channel) + => channel < 0.018F ? 4500F * channel : (1.099F * channel) - 0.099F; + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs new file mode 100644 index 0000000000..090efcd793 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// Rec. 709 (ITU-R Recommendation BT.709) working space. + /// + public sealed class Rec709WorkingSpace : RgbWorkingSpaceBase + { + /// + /// Initializes a new instance of the class. + /// + /// The reference white point. + /// The chromaticity of the rgb primaries. + public Rec709WorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) + : base(referenceWhite, chromaticityCoordinates) + { + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Compress(float channel) => Rec709Companding.Compress(channel); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Expand(float channel) => Rec709Companding.Expand(channel); + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpaceBase.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpaceBase.cs new file mode 100644 index 0000000000..5a89321c8f --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/RgbWorkingSpaceBase.cs @@ -0,0 +1,83 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// Base class for all implementations of . + /// + public abstract class RgbWorkingSpaceBase + { + /// + /// Initializes a new instance of the class. + /// + /// The reference white point. + /// The chromaticity of the rgb primaries. + protected RgbWorkingSpaceBase(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) + { + this.WhitePoint = referenceWhite; + this.ChromaticityCoordinates = chromaticityCoordinates; + } + + /// + /// Gets the reference white point + /// + public CieXyz WhitePoint { get; } + + /// + /// Gets the chromaticity of the rgb primaries. + /// + public RgbPrimariesChromaticityCoordinates ChromaticityCoordinates { get; } + + /// + /// Expands a companded channel to its linear equivalent with respect to the energy. + /// + /// + /// For more info see: + /// + /// + /// The channel value. + /// The representing the linear channel value. + public abstract float Expand(float channel); + + /// + /// Compresses an uncompanded channel (linear) to its nonlinear equivalent (depends on the RGB color system). + /// + /// + /// For more info see: + /// + /// + /// The channel value. + /// The representing the nonlinear channel value. + public abstract float Compress(float channel); + + /// + public override bool Equals(object obj) + { + if (obj is null) + { + return false; + } + + if (ReferenceEquals(this, obj)) + { + return true; + } + + if (obj is RgbWorkingSpaceBase other) + { + return this.WhitePoint.Equals(other.WhitePoint) + && this.ChromaticityCoordinates.Equals(other.ChromaticityCoordinates); + } + + return false; + } + + /// + public override int GetHashCode() + { + int hash = this.WhitePoint.GetHashCode(); + return HashHelpers.Combine(hash, this.ChromaticityCoordinates.GetHashCode()); + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs new file mode 100644 index 0000000000..61b3b1cf1d --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs @@ -0,0 +1,35 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// Implements sRGB companding + /// + /// + /// For more info see: + /// + /// + /// + public static class SRgbCompanding + { + /// + /// Expands a companded channel to its linear equivalent with respect to the energy. + /// + /// The channel value + /// The representing the linear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Expand(float channel) => channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); + + /// + /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. + /// + /// The channel value + /// The representing the nonlinear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Compress(float channel) => channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs new file mode 100644 index 0000000000..369f91c764 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs @@ -0,0 +1,31 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +{ + /// + /// The sRgb working space. + /// + public sealed class SRgbWorkingSpace : RgbWorkingSpaceBase + { + /// + /// Initializes a new instance of the class. + /// + /// The reference white point. + /// The chromaticity of the rgb primaries. + public SRgbWorkingSpace(CieXyz referenceWhite, RgbPrimariesChromaticityCoordinates chromaticityCoordinates) + : base(referenceWhite, chromaticityCoordinates) + { + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Compress(float channel) => SRgbCompanding.Compress(channel); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public override float Expand(float channel) => SRgbCompanding.Expand(channel); + } +} diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index 9ecef0a31e..09a2d83cb3 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -9,7 +9,7 @@ using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; namespace SixLabors.ImageSharp.ColorSpaces { /// - /// Represents an linear Rgb color with specified working space + /// Represents an linear Rgb color with specified working space /// public readonly struct LinearRgb : IEquatable { @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The default LinearRgb working space. /// - public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; + public static readonly RgbWorkingSpaceBase DefaultWorkingSpace = RgbWorkingSpaces.SRgb; /// /// Gets the red component. @@ -42,7 +42,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Gets the LinearRgb color space /// - public readonly RgbWorkingSpace WorkingSpace; + public readonly RgbWorkingSpaceBase WorkingSpace; /// /// Initializes a new instance of the struct. @@ -64,7 +64,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The blue component ranging between 0 and 1. /// The rgb working space. [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(float r, float g, float b, RgbWorkingSpace workingSpace) + public LinearRgb(float r, float g, float b, RgbWorkingSpaceBase workingSpace) : this(new Vector3(r, g, b), workingSpace) { } @@ -85,7 +85,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The vector representing the r, g, b components. /// The LinearRgb working space. [MethodImpl(InliningOptions.ShortMethod)] - public LinearRgb(Vector3 vector, RgbWorkingSpace workingSpace) + public LinearRgb(Vector3 vector, RgbWorkingSpaceBase workingSpace) { // Clamp to 0-1 range. vector = Vector3.Clamp(vector, Min, Max); diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 5a02936993..0700830517 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -10,7 +10,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.ColorSpaces { /// - /// Represents an RGB color with specified working space. + /// Represents an RGB color with specified working space. /// public readonly struct Rgb : IEquatable { @@ -20,7 +20,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// The default rgb working space /// - public static readonly RgbWorkingSpace DefaultWorkingSpace = RgbWorkingSpaces.SRgb; + public static readonly RgbWorkingSpaceBase DefaultWorkingSpace = RgbWorkingSpaces.SRgb; /// /// Gets the red component. @@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// /// Gets the Rgb color space /// - public readonly RgbWorkingSpace WorkingSpace; + public readonly RgbWorkingSpaceBase WorkingSpace; /// /// Initializes a new instance of the struct. @@ -65,7 +65,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The blue component ranging between 0 and 1. /// The rgb working space. [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(float r, float g, float b, RgbWorkingSpace workingSpace) + public Rgb(float r, float g, float b, RgbWorkingSpaceBase workingSpace) : this(new Vector3(r, g, b), workingSpace) { } @@ -86,7 +86,7 @@ namespace SixLabors.ImageSharp.ColorSpaces /// The vector representing the r, g, b components. /// The rgb working space. [MethodImpl(InliningOptions.ShortMethod)] - public Rgb(Vector3 vector, RgbWorkingSpace workingSpace) + public Rgb(Vector3 vector, RgbWorkingSpaceBase workingSpace) { vector = Vector3.Clamp(vector, Min, Max); this.R = vector.X; diff --git a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs index 62bf7d6292..11884ca819 100644 --- a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs +++ b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs @@ -19,97 +19,97 @@ namespace SixLabors.ImageSharp.ColorSpaces /// Uses proper companding function, according to: /// /// - public static readonly RgbWorkingSpace SRgb = new RgbWorkingSpace(Illuminants.D65, new SRgbCompanding(), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + public static readonly RgbWorkingSpaceBase SRgb = new SRgbWorkingSpace(Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); /// /// Simplified sRgb working space (uses gamma companding instead of ). /// See also . /// - public static readonly RgbWorkingSpace SRgbSimplified = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + public static readonly RgbWorkingSpaceBase SRgbSimplified = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.3000F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); /// /// Rec. 709 (ITU-R Recommendation BT.709) working space. /// - public static readonly RgbWorkingSpace Rec709 = new RgbWorkingSpace(Illuminants.D65, new Rec709Companding(), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.64F, 0.33F), new CieXyChromaticityCoordinates(0.30F, 0.60F), new CieXyChromaticityCoordinates(0.15F, 0.06F))); + public static readonly RgbWorkingSpaceBase Rec709 = new Rec709WorkingSpace(Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.64F, 0.33F), new CieXyChromaticityCoordinates(0.30F, 0.60F), new CieXyChromaticityCoordinates(0.15F, 0.06F))); /// /// Rec. 2020 (ITU-R Recommendation BT.2020F) working space. /// - public static readonly RgbWorkingSpace Rec2020 = new RgbWorkingSpace(Illuminants.D65, new Rec2020Companding(), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.708F, 0.292F), new CieXyChromaticityCoordinates(0.170F, 0.797F), new CieXyChromaticityCoordinates(0.131F, 0.046F))); + public static readonly RgbWorkingSpaceBase Rec2020 = new Rec2020WorkingSpace(Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.708F, 0.292F), new CieXyChromaticityCoordinates(0.170F, 0.797F), new CieXyChromaticityCoordinates(0.131F, 0.046F))); /// /// ECI Rgb v2 working space. /// - public static readonly RgbWorkingSpace ECIRgbv2 = new RgbWorkingSpace(Illuminants.D50, new LCompanding(), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); + public static readonly RgbWorkingSpaceBase ECIRgbv2 = new LWorkingSpace(Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); /// /// Adobe Rgb (1998) working space. /// - public static readonly RgbWorkingSpace AdobeRgb1998 = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + public static readonly RgbWorkingSpaceBase AdobeRgb1998 = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); /// /// Apple sRgb working space. /// - public static readonly RgbWorkingSpace ApplesRgb = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(1.8F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6250F, 0.3400F), new CieXyChromaticityCoordinates(0.2800F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); + public static readonly RgbWorkingSpaceBase ApplesRgb = new GammaWorkingSpace(1.8F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6250F, 0.3400F), new CieXyChromaticityCoordinates(0.2800F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); /// /// Best Rgb working space. /// - public static readonly RgbWorkingSpace BestRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.2150F, 0.7750F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); + public static readonly RgbWorkingSpaceBase BestRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.2150F, 0.7750F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); /// /// Beta Rgb working space. /// - public static readonly RgbWorkingSpace BetaRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6888F, 0.3112F), new CieXyChromaticityCoordinates(0.1986F, 0.7551F), new CieXyChromaticityCoordinates(0.1265F, 0.0352F))); + public static readonly RgbWorkingSpaceBase BetaRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6888F, 0.3112F), new CieXyChromaticityCoordinates(0.1986F, 0.7551F), new CieXyChromaticityCoordinates(0.1265F, 0.0352F))); /// /// Bruce Rgb working space. /// - public static readonly RgbWorkingSpace BruceRgb = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2800F, 0.6500F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + public static readonly RgbWorkingSpaceBase BruceRgb = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2800F, 0.6500F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); /// /// CIE Rgb working space. /// - public static readonly RgbWorkingSpace CIERgb = new RgbWorkingSpace(Illuminants.E, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.2740F, 0.7170F), new CieXyChromaticityCoordinates(0.1670F, 0.0090F))); + public static readonly RgbWorkingSpaceBase CIERgb = new GammaWorkingSpace(2.2F, Illuminants.E, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.2740F, 0.7170F), new CieXyChromaticityCoordinates(0.1670F, 0.0090F))); /// /// ColorMatch Rgb working space. /// - public static readonly RgbWorkingSpace ColorMatchRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(1.8F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.2950F, 0.6050F), new CieXyChromaticityCoordinates(0.1500F, 0.0750F))); + public static readonly RgbWorkingSpaceBase ColorMatchRgb = new GammaWorkingSpace(1.8F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.2950F, 0.6050F), new CieXyChromaticityCoordinates(0.1500F, 0.0750F))); /// /// Don Rgb 4 working space. /// - public static readonly RgbWorkingSpace DonRgb4 = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6960F, 0.3000F), new CieXyChromaticityCoordinates(0.2150F, 0.7650F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); + public static readonly RgbWorkingSpaceBase DonRgb4 = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6960F, 0.3000F), new CieXyChromaticityCoordinates(0.2150F, 0.7650F), new CieXyChromaticityCoordinates(0.1300F, 0.0350F))); /// /// Ekta Space PS5 working space. /// - public static readonly RgbWorkingSpace EktaSpacePS5 = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6950F, 0.3050F), new CieXyChromaticityCoordinates(0.2600F, 0.7000F), new CieXyChromaticityCoordinates(0.1100F, 0.0050F))); + public static readonly RgbWorkingSpaceBase EktaSpacePS5 = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6950F, 0.3050F), new CieXyChromaticityCoordinates(0.2600F, 0.7000F), new CieXyChromaticityCoordinates(0.1100F, 0.0050F))); /// /// NTSC Rgb working space. /// - public static readonly RgbWorkingSpace NTSCRgb = new RgbWorkingSpace(Illuminants.C, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); + public static readonly RgbWorkingSpaceBase NTSCRgb = new GammaWorkingSpace(2.2F, Illuminants.C, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6700F, 0.3300F), new CieXyChromaticityCoordinates(0.2100F, 0.7100F), new CieXyChromaticityCoordinates(0.1400F, 0.0800F))); /// /// PAL/SECAM Rgb working space. /// - public static readonly RgbWorkingSpace PALSECAMRgb = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2900F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); + public static readonly RgbWorkingSpaceBase PALSECAMRgb = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6400F, 0.3300F), new CieXyChromaticityCoordinates(0.2900F, 0.6000F), new CieXyChromaticityCoordinates(0.1500F, 0.0600F))); /// /// ProPhoto Rgb working space. /// - public static readonly RgbWorkingSpace ProPhotoRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(1.8F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.1596F, 0.8404F), new CieXyChromaticityCoordinates(0.0366F, 0.0001F))); + public static readonly RgbWorkingSpaceBase ProPhotoRgb = new GammaWorkingSpace(1.8F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7347F, 0.2653F), new CieXyChromaticityCoordinates(0.1596F, 0.8404F), new CieXyChromaticityCoordinates(0.0366F, 0.0001F))); /// /// SMPTE-C Rgb working space. /// - public static readonly RgbWorkingSpace SMPTECRgb = new RgbWorkingSpace(Illuminants.D65, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.3100F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); + public static readonly RgbWorkingSpaceBase SMPTECRgb = new GammaWorkingSpace(2.2F, Illuminants.D65, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.6300F, 0.3400F), new CieXyChromaticityCoordinates(0.3100F, 0.5950F), new CieXyChromaticityCoordinates(0.1550F, 0.0700F))); /// /// Wide Gamut Rgb working space. /// - public static readonly RgbWorkingSpace WideGamutRgb = new RgbWorkingSpace(Illuminants.D50, new GammaCompanding(2.2F), new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F))); + public static readonly RgbWorkingSpaceBase WideGamutRgb = new GammaWorkingSpace(2.2F, Illuminants.D50, new RgbPrimariesChromaticityCoordinates(new CieXyChromaticityCoordinates(0.7350F, 0.2650F), new CieXyChromaticityCoordinates(0.1150F, 0.8260F), new CieXyChromaticityCoordinates(0.1570F, 0.0180F))); } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs index 19b8c2272e..57da2ff170 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/ApproximateColorspaceComparer.cs @@ -27,7 +27,8 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion IEqualityComparer, IEqualityComparer, IEqualityComparer, - IEqualityComparer + IEqualityComparer, + IEqualityComparer { private readonly float Epsilon; @@ -205,20 +206,30 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion public int GetHashCode(RgbPrimariesChromaticityCoordinates obj) => obj.GetHashCode(); /// - public bool Equals(RgbWorkingSpace x, RgbWorkingSpace y) + public bool Equals(GammaWorkingSpace x, GammaWorkingSpace y) { - if (x is RgbWorkingSpace g1 && y is RgbWorkingSpace g2) + if (x is GammaWorkingSpace g1 && y is GammaWorkingSpace g2) { - return this.Equals(g1.WhitePoint, g2.WhitePoint) + return this.Equals(g1.Gamma, g2.Gamma) + && this.Equals(g1.WhitePoint, g2.WhitePoint) && this.Equals(g1.ChromaticityCoordinates, g2.ChromaticityCoordinates); } + return false; + } + + /// + public int GetHashCode(GammaWorkingSpace obj) => obj.GetHashCode(); + + /// + public bool Equals(RgbWorkingSpaceBase x, RgbWorkingSpaceBase y) + { return this.Equals(x.WhitePoint, y.WhitePoint) && this.Equals(x.ChromaticityCoordinates, y.ChromaticityCoordinates); } /// - public int GetHashCode(RgbWorkingSpace obj) => obj.GetHashCode(); + public int GetHashCode(RgbWorkingSpaceBase obj) => obj.GetHashCode(); private bool Equals(float x, float y) { diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs b/tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs index adf0263a06..125f8f9941 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs @@ -18,38 +18,51 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion [Fact] public void Rec2020CompandingIsCorrect() { - CompandingIsCorrectImpl(new Rec2020Companding(), .667F, .4484759F, .3937096F); + const float input = .667F; + float e = Rec2020Companding.Expand(input); + float c = Rec2020Companding.Compress(e); + CompandingIsCorrectImpl(e, c, .4484759F, .3937096F); } [Fact] public void Rec709CompandingIsCorrect() { - CompandingIsCorrectImpl(new Rec709Companding(), .667F, .4483577F, .3937451F); + const float input = .667F; + float e = Rec709Companding.Expand(input); + float c = Rec709Companding.Compress(e); + CompandingIsCorrectImpl(e, c, .4483577F, .3937451F); } [Fact] public void SRgbCompandingIsCorrect() { - CompandingIsCorrectImpl(new SRgbCompanding(), .667F, .40242353F, .667F); + const float input = .667F; + float e = SRgbCompanding.Expand(input); + float c = SRgbCompanding.Compress(e); + CompandingIsCorrectImpl(e, c, .40242353F, .667F); } [Fact] public void GammaCompandingIsCorrect() { - CompandingIsCorrectImpl(new GammaCompanding(2.2F), .667F, .41027668F, .667F); + const float gamma = 2.2F; + const float input = .667F; + float e = GammaCompanding.Expand(input, gamma); + float c = GammaCompanding.Compress(e, gamma); + CompandingIsCorrectImpl(e, c, .41027668F, .667F); } [Fact] public void LCompandingIsCorrect() { - CompandingIsCorrectImpl(new LCompanding(), .667F, .36236193F, .58908917F); + const float input = .667F; + float e = LCompanding.Expand(input); + float c = LCompanding.Compress(e); + CompandingIsCorrectImpl(e, c, .36236193F, .58908917F); } - private static void CompandingIsCorrectImpl(ICompanding companding, float input, float expanded, float compressed) + private static void CompandingIsCorrectImpl(float e, float c, float expanded, float compressed) { - float e = companding.Expand(input); - float c = companding.Compress(e); - Assert.Equal(expanded, e, FloatComparer); Assert.Equal(compressed, c, FloatComparer); } diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs index f0e255c7c6..854e57d8f5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Collections.Generic; using System.Numerics; @@ -20,11 +19,9 @@ namespace SixLabors.ImageSharp.Tests /// Initializes a new instance of the class. /// /// The comparison error difference epsilon to use. - public ApproximateFloatComparer(float epsilon = 1f) - { - this.Epsilon = epsilon; - } + public ApproximateFloatComparer(float epsilon = 1f) => this.Epsilon = epsilon; + /// public bool Equals(float x, float y) { float d = x - y; @@ -32,19 +29,13 @@ namespace SixLabors.ImageSharp.Tests return d >= -this.Epsilon && d <= this.Epsilon; } - public int GetHashCode(float obj) - { - return obj.GetHashCode(); - } + /// + public int GetHashCode(float obj) => obj.GetHashCode(); - public bool Equals(Vector4 x, Vector4 y) - { - return this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z) && this.Equals(x.W, y.W); - } + /// + public bool Equals(Vector4 x, Vector4 y) => this.Equals(x.X, y.X) && this.Equals(x.Y, y.Y) && this.Equals(x.Z, y.Z) && this.Equals(x.W, y.W); - public int GetHashCode(Vector4 obj) - { - return obj.GetHashCode(); - } + /// + public int GetHashCode(Vector4 obj) => obj.GetHashCode(); } } \ No newline at end of file From 01a6d8b285e6a01683c9a93191ce87709ec39a9e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 10 Oct 2018 13:19:16 +0100 Subject: [PATCH 168/185] Unify sRGB companding --- .../Common/Extensions/Vector4Extensions.cs | 78 ++++++------------- .../Helpers/Vector4ExtensionsTests.cs | 2 - 2 files changed, 25 insertions(+), 55 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs index f9bbdfc040..50afc6a4b4 100644 --- a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs +++ b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs @@ -5,7 +5,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; - +using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp @@ -55,8 +55,10 @@ namespace SixLabors.ImageSharp for (int i = 0; i < vectors.Length; i++) { ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - var s = new Vector4(v.W); - s.W = 1; + var s = new Vector4(v.W) + { + W = 1 + }; v *= s; } } @@ -73,8 +75,10 @@ namespace SixLabors.ImageSharp for (int i = 0; i < vectors.Length; i++) { ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - var s = new Vector4(1 / v.W); - s.W = 1; + var s = new Vector4(1 / v.W) + { + W = 1 + }; v *= s; } } @@ -90,7 +94,11 @@ namespace SixLabors.ImageSharp public static Vector4 Compress(this Vector4 linear) { // TODO: Is there a faster way to do this? - return new Vector4(Compress(linear.X), Compress(linear.Y), Compress(linear.Z), linear.W); + return new Vector4( + SRgbCompanding.Compress(linear.X), + SRgbCompanding.Compress(linear.Y), + SRgbCompanding.Compress(linear.Z), + linear.W); } /// @@ -104,7 +112,11 @@ namespace SixLabors.ImageSharp public static Vector4 Expand(this Vector4 gamma) { // TODO: Is there a faster way to do this? - return new Vector4(Expand(gamma.X), Expand(gamma.Y), Expand(gamma.Z), gamma.W); + return new Vector4( + SRgbCompanding.Expand(gamma.X), + SRgbCompanding.Expand(gamma.Y), + SRgbCompanding.Expand(gamma.Z), + gamma.W); } /// @@ -118,9 +130,9 @@ namespace SixLabors.ImageSharp for (int i = 0; i < vectors.Length; i++) { ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - v.X = Compress(v.X); - v.Y = Compress(v.Y); - v.Z = Compress(v.Z); + v.X = SRgbCompanding.Compress(v.X); + v.Y = SRgbCompanding.Compress(v.Y); + v.Z = SRgbCompanding.Compress(v.Z); } } @@ -135,50 +147,10 @@ namespace SixLabors.ImageSharp for (int i = 0; i < vectors.Length; i++) { ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - v.X = Expand(v.X); - v.Y = Expand(v.Y); - v.Z = Expand(v.Z); - } - } - - /// - /// Gets the compressed sRGB value from an linear signal. - /// - /// - /// - /// The signal value to compress. - /// - /// The . - /// - [MethodImpl(InliningOptions.ShortMethod)] - private static float Compress(float signal) - { - if (signal <= 0.0031308F) - { - return signal * 12.92F; + v.X = SRgbCompanding.Expand(v.X); + v.Y = SRgbCompanding.Expand(v.Y); + v.Z = SRgbCompanding.Expand(v.Z); } - - return (1.055F * MathF.Pow(signal, 0.41666666F)) - 0.055F; - } - - /// - /// Gets the expanded linear value from an sRGB signal. - /// - /// - /// - /// The signal value to expand. - /// - /// The . - /// - [MethodImpl(InliningOptions.ShortMethod)] - private static float Expand(float signal) - { - if (signal <= 0.04045F) - { - return signal / 12.92F; - } - - return MathF.Pow((signal + 0.055F) / 1.055F, 2.4F); } } } \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs b/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs index 68f71d88f8..2d2a2795d8 100644 --- a/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs @@ -70,7 +70,5 @@ namespace SixLabors.ImageSharp.Tests.Helpers Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); } - - } } From b0b2d55cbb184ac96376e3cdae823547cd821013 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 11 Oct 2018 10:36:02 +0100 Subject: [PATCH 169/185] Move compaing classes and migrate vector code to srgbcompaning --- .../GammaCompanding.cs | 2 +- .../LCompanding.cs | 3 +- .../Rec2020Companding.cs | 2 +- .../Rec709Companding.cs | 2 +- .../ColorSpaces/Companding/SRgbCompanding.cs | 89 ++++++++++ .../WorkingSpaces/GammaWorkingSpace.cs | 1 + .../WorkingSpaces/LWorkingSpace.cs | 1 + .../WorkingSpaces/Rec2020WorkingSpace.cs | 1 + .../WorkingSpaces/Rec709WorkingSpace.cs | 1 + .../WorkingSpaces/SRgbCompanding.cs | 35 ---- .../WorkingSpaces/SRgbWorkingSpace.cs | 1 + .../ColorSpaces/RgbWorkingSpaces.cs | 1 + .../Common/Extensions/Vector4Extensions.cs | 156 ------------------ src/ImageSharp/Common/Helpers/Vector4Utils.cs | 86 ++++++++++ .../Convolution/Convolution2DProcessor.cs | 4 +- .../Convolution/Convolution2PassProcessor.cs | 7 +- .../Convolution/ConvolutionProcessor.cs | 4 +- .../Transforms/AffineTransformProcessor.cs | 7 +- .../ProjectiveTransformProcessor.cs | 12 +- .../Processors/Transforms/ResizeProcessor.cs | 9 +- .../CompandingTests.cs | 49 +++++- .../Helpers/Vector4ExtensionsTests.cs | 74 --------- .../Helpers/Vector4UtilsTests.cs | 44 +++++ 23 files changed, 287 insertions(+), 304 deletions(-) rename src/ImageSharp/ColorSpaces/{Conversion/Implementation/WorkingSpaces => Companding}/GammaCompanding.cs (95%) rename src/ImageSharp/ColorSpaces/{Conversion/Implementation/WorkingSpaces => Companding}/LCompanding.cs (93%) rename src/ImageSharp/ColorSpaces/{Conversion/Implementation/WorkingSpaces => Companding}/Rec2020Companding.cs (95%) rename src/ImageSharp/ColorSpaces/{Conversion/Implementation/WorkingSpaces => Companding}/Rec709Companding.cs (95%) create mode 100644 src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs delete mode 100644 src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs delete mode 100644 src/ImageSharp/Common/Extensions/Vector4Extensions.cs create mode 100644 src/ImageSharp/Common/Helpers/Vector4Utils.cs rename tests/ImageSharp.Tests/Colorspaces/{Conversion => Companding}/CompandingTests.cs (59%) delete mode 100644 tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs create mode 100644 tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs similarity index 95% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaCompanding.cs rename to src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs index d9babc7ef2..13cca1582d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/GammaCompanding.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Companding { /// /// Implements gamma companding diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs similarity index 93% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LCompanding.cs rename to src/ImageSharp/ColorSpaces/Companding/LCompanding.cs index ebe7ebe938..9e2cf8ad86 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LCompanding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/LCompanding.cs @@ -3,8 +3,9 @@ using System; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.ColorSpaces.Conversion; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Companding { /// /// Implements L* companding diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs similarity index 95% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020Companding.cs rename to src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs index ba77e78f0b..a3a9121727 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020Companding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/Rec2020Companding.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Companding { /// /// Implements Rec. 2020 companding function (for 12-bits). diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709Companding.cs b/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs similarity index 95% rename from src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709Companding.cs rename to src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs index e281339a61..e2e802d08a 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709Companding.cs +++ b/src/ImageSharp/ColorSpaces/Companding/Rec709Companding.cs @@ -4,7 +4,7 @@ using System; using System.Runtime.CompilerServices; -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation +namespace SixLabors.ImageSharp.ColorSpaces.Companding { /// /// Implements the Rec. 709 companding function. diff --git a/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs new file mode 100644 index 0000000000..5ae4629137 --- /dev/null +++ b/src/ImageSharp/ColorSpaces/Companding/SRgbCompanding.cs @@ -0,0 +1,89 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp.ColorSpaces.Companding +{ + /// + /// Implements sRGB companding + /// + /// + /// For more info see: + /// + /// + /// + public static class SRgbCompanding + { + /// + /// Expands the companded vectors to their linear equivalents with respect to the energy. + /// + /// The span of vectors. + [MethodImpl(InliningOptions.ShortMethod)] + public static void Expand(Span vectors) + { + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + v.X = Expand(v.X); + v.Y = Expand(v.Y); + v.Z = Expand(v.Z); + } + } + + /// + /// Compresses the uncompanded vectors to their nonlinear equivalents with respect to the energy. + /// + /// The span of vectors. + [MethodImpl(InliningOptions.ShortMethod)] + public static void Compress(Span vectors) + { + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + v.X = Compress(v.X); + v.Y = Compress(v.Y); + v.Z = Compress(v.Z); + } + } + + /// + /// Expands a companded vector to its linear equivalent with respect to the energy. + /// + /// The vector. + /// The representing the linear channel values. + [MethodImpl(InliningOptions.ShortMethod)] + public static Vector4 Expand(Vector4 vector) => new Vector4(Expand(vector.X), Expand(vector.Y), Expand(vector.Z), vector.W); + + /// + /// Compresses an uncompanded vector (linear) to its nonlinear equivalent. + /// + /// The vector. + /// The representing the nonlinear channel values. + [MethodImpl(InliningOptions.ShortMethod)] + public static Vector4 Compress(Vector4 vector) => new Vector4(Compress(vector.X), Compress(vector.Y), Compress(vector.Z), vector.W); + + /// + /// Expands a companded channel to its linear equivalent with respect to the energy. + /// + /// The channel value. + /// The representing the linear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Expand(float channel) => channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); + + /// + /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. + /// + /// The channel value. + /// The representing the nonlinear channel value. + [MethodImpl(InliningOptions.ShortMethod)] + public static float Compress(float channel) => channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; + } +} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs index 6d8b25e9db..73aa60b6cb 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/GammaWorkingSpace.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.ColorSpaces.Companding; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs index cbc4be5967..16617ea242 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/LWorkingSpace.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.ColorSpaces.Companding; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs index 11f1f84016..9ba1ff8811 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec2020WorkingSpace.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.ColorSpaces.Companding; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs index 090efcd793..88623e958d 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/Rec709WorkingSpace.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.ColorSpaces.Companding; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs deleted file mode 100644 index 61b3b1cf1d..0000000000 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbCompanding.cs +++ /dev/null @@ -1,35 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Runtime.CompilerServices; - -namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation -{ - /// - /// Implements sRGB companding - /// - /// - /// For more info see: - /// - /// - /// - public static class SRgbCompanding - { - /// - /// Expands a companded channel to its linear equivalent with respect to the energy. - /// - /// The channel value - /// The representing the linear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Expand(float channel) => channel <= 0.04045F ? channel / 12.92F : MathF.Pow((channel + 0.055F) / 1.055F, 2.4F); - - /// - /// Compresses an uncompanded channel (linear) to its nonlinear equivalent. - /// - /// The channel value - /// The representing the nonlinear channel value. - [MethodImpl(InliningOptions.ShortMethod)] - public static float Compress(float channel) => channel <= 0.0031308F ? 12.92F * channel : (1.055F * MathF.Pow(channel, 0.416666666666667F)) - 0.055F; - } -} \ No newline at end of file diff --git a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs index 369f91c764..b44db06817 100644 --- a/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs +++ b/src/ImageSharp/ColorSpaces/Conversion/Implementation/WorkingSpaces/SRgbWorkingSpace.cs @@ -2,6 +2,7 @@ // Licensed under the Apache License, Version 2.0. using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.ColorSpaces.Companding; namespace SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation { diff --git a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs index 11884ca819..ee3822c152 100644 --- a/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs +++ b/src/ImageSharp/ColorSpaces/RgbWorkingSpaces.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. +using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; // ReSharper disable InconsistentNaming diff --git a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs b/src/ImageSharp/Common/Extensions/Vector4Extensions.cs deleted file mode 100644 index 50afc6a4b4..0000000000 --- a/src/ImageSharp/Common/Extensions/Vector4Extensions.cs +++ /dev/null @@ -1,156 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp -{ - /// - /// Extension methods for the struct. - /// - internal static class Vector4Extensions - { - /// - /// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact. - /// - /// The to premultiply - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public static Vector4 Premultiply(this Vector4 source) - { - float w = source.W; - Vector4 premultiplied = source * w; - premultiplied.W = w; - return premultiplied; - } - - /// - /// Reverses the result of premultiplying a vector via . - /// - /// The to premultiply - /// The - [MethodImpl(InliningOptions.ShortMethod)] - public static Vector4 UnPremultiply(this Vector4 source) - { - float w = source.W; - Vector4 unpremultiplied = source / w; - unpremultiplied.W = w; - return unpremultiplied; - } - - /// - /// Bulk variant of - /// - /// The span of vectors - public static void Premultiply(Span vectors) - { - // TODO: This method can be AVX2 optimized using Vector - ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); - - for (int i = 0; i < vectors.Length; i++) - { - ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - var s = new Vector4(v.W) - { - W = 1 - }; - v *= s; - } - } - - /// - /// Bulk variant of - /// - /// The span of vectors - public static void UnPremultiply(Span vectors) - { - // TODO: This method can be AVX2 optimized using Vector - ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); - - for (int i = 0; i < vectors.Length; i++) - { - ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - var s = new Vector4(1 / v.W) - { - W = 1 - }; - v *= s; - } - } - - /// - /// Compresses a linear color signal to its sRGB equivalent. - /// - /// - /// - /// The whose signal to compress. - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Vector4 Compress(this Vector4 linear) - { - // TODO: Is there a faster way to do this? - return new Vector4( - SRgbCompanding.Compress(linear.X), - SRgbCompanding.Compress(linear.Y), - SRgbCompanding.Compress(linear.Z), - linear.W); - } - - /// - /// Expands an sRGB color signal to its linear equivalent. - /// - /// - /// - /// The whose signal to expand. - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Vector4 Expand(this Vector4 gamma) - { - // TODO: Is there a faster way to do this? - return new Vector4( - SRgbCompanding.Expand(gamma.X), - SRgbCompanding.Expand(gamma.Y), - SRgbCompanding.Expand(gamma.Z), - gamma.W); - } - - /// - /// Bulk variant of - /// - /// The span of vectors - public static void Compress(Span vectors) - { - ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); - - for (int i = 0; i < vectors.Length; i++) - { - ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - v.X = SRgbCompanding.Compress(v.X); - v.Y = SRgbCompanding.Compress(v.Y); - v.Z = SRgbCompanding.Compress(v.Z); - } - } - - /// - /// Bulk variant of - /// - /// The span of vectors - public static void Expand(Span vectors) - { - ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); - - for (int i = 0; i < vectors.Length; i++) - { - ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - v.X = SRgbCompanding.Expand(v.X); - v.Y = SRgbCompanding.Expand(v.Y); - v.Z = SRgbCompanding.Expand(v.Z); - } - } - } -} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/Vector4Utils.cs b/src/ImageSharp/Common/Helpers/Vector4Utils.cs new file mode 100644 index 0000000000..4545d797c2 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/Vector4Utils.cs @@ -0,0 +1,86 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp +{ + /// + /// Utility methods for the struct. + /// + internal static class Vector4Utils + { + /// + /// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact. + /// + /// The to premultiply + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static Vector4 Premultiply(Vector4 source) + { + float w = source.W; + Vector4 premultiplied = source * w; + premultiplied.W = w; + return premultiplied; + } + + /// + /// Reverses the result of premultiplying a vector via . + /// + /// The to premultiply + /// The + [MethodImpl(InliningOptions.ShortMethod)] + public static Vector4 UnPremultiply(Vector4 source) + { + float w = source.W; + Vector4 unpremultiplied = source / w; + unpremultiplied.W = w; + return unpremultiplied; + } + + /// + /// Bulk variant of + /// + /// The span of vectors + [MethodImpl(InliningOptions.ShortMethod)] + public static void Premultiply(Span vectors) + { + // TODO: This method can be AVX2 optimized using Vector + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + var s = new Vector4(v.W) + { + W = 1 + }; + v *= s; + } + } + + /// + /// Bulk variant of + /// + /// The span of vectors + [MethodImpl(InliningOptions.ShortMethod)] + public static void UnPremultiply(Span vectors) + { + // TODO: This method can be AVX2 optimized using Vector + ref Vector4 baseRef = ref MemoryMarshal.GetReference(vectors); + + for (int i = 0; i < vectors.Length; i++) + { + ref Vector4 v = ref Unsafe.Add(ref baseRef, i); + var s = new Vector4(1 / v.W) + { + W = 1 + }; + v *= s; + } + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index d2282ec0e1..c358b316c1 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution int offsetX = x + fxr; offsetX = offsetX.Clamp(0, maxX); - Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); + Vector4 currentColor = Vector4Utils.Premultiply(sourceOffsetRow[offsetX].ToVector4()); if (fy < kernelXHeight) { @@ -128,7 +128,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution ref TPixel pixel = ref targetRow[x]; pixel.PackFromVector4( - new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); + Vector4Utils.UnPremultiply(new Vector4(red, green, blue, sourceRow[x].ToVector4().W))); } } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index e45bb3ab2e..3135ff6148 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -3,14 +3,11 @@ using System; using System.Numerics; -using System.Threading.Tasks; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution @@ -114,13 +111,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution offsetX = offsetX.Clamp(0, maxX); - Vector4 currentColor = row[offsetX].ToVector4().Premultiply(); + Vector4 currentColor = Vector4Utils.Premultiply(row[offsetX].ToVector4()); destination += kernel[fy, fx] * currentColor; } } ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4(destination.UnPremultiply()); + pixel.PackFromVector4(Vector4Utils.UnPremultiply(destination)); } } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index bac9a86cfe..1d1755ccd6 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -87,7 +87,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution offsetX = offsetX.Clamp(0, maxX); - Vector4 currentColor = sourceOffsetRow[offsetX].ToVector4().Premultiply(); + Vector4 currentColor = Vector4Utils.Premultiply(sourceOffsetRow[offsetX].ToVector4()); currentColor *= this.KernelXY[fy, fx]; red += currentColor.X; @@ -98,7 +98,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution ref TPixel pixel = ref targetRow[x]; pixel.PackFromVector4( - new Vector4(red, green, blue, sourceRow[x].ToVector4().W).UnPremultiply()); + Vector4Utils.UnPremultiply(new Vector4(red, green, blue, sourceRow[x].ToVector4().W))); } } }); diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 3469161e6d..225c687d87 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; @@ -207,18 +206,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int xx = 0, i = minX; i <= maxX; i++, xx++) { float xWeight = Unsafe.Add(ref xSpanRef, xx); - var vector = source[i, j].ToVector4(); // Values are first premultiplied to prevent darkening of edge pixels - Vector4 multiplied = vector.Premultiply(); - sum += multiplied * xWeight * yWeight; + sum += Vector4Utils.Premultiply(source[i, j].ToVector4()) * xWeight * yWeight; } } ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); // Reverse the premultiplication - dest.PackFromVector4(sum.UnPremultiply()); + dest.PackFromVector4(Vector4Utils.UnPremultiply(sum)); } } }); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index b03dec032f..f860264af5 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -7,7 +7,6 @@ using System.Linq; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Threading.Tasks; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; @@ -216,18 +215,16 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms for (int xx = 0, i = minX; i <= maxX; i++, xx++) { float xWeight = Unsafe.Add(ref xSpanRef, xx); - var vector = source[i, j].ToVector4(); // Values are first premultiplied to prevent darkening of edge pixels - Vector4 multiplied = vector.Premultiply(); - sum += multiplied * xWeight * yWeight; + sum += Vector4Utils.Premultiply(source[i, j].ToVector4()) * xWeight * yWeight; } } ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); // Reverse the premultiplication - dest.PackFromVector4(sum.UnPremultiply()); + dest.PackFromVector4(Vector4Utils.UnPremultiply(sum)); } } }); @@ -242,9 +239,6 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms /// /// The . /// - protected virtual Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) - { - return this.TransformMatrix; - } + protected virtual Matrix4x4 GetProcessingMatrix(Rectangle sourceRectangle, Rectangle destinationRectangle) => this.TransformMatrix; } } \ No newline at end of file diff --git a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs index d353c1fd2c..812c0578b2 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ResizeProcessor.cs @@ -9,6 +9,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.ColorSpaces.Companding; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; @@ -257,13 +258,13 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Span tempRowSpan = tempRowBuffer.Span; PixelOperations.Instance.ToVector4(sourceRow, tempRowSpan, sourceRow.Length); - Vector4Extensions.Premultiply(tempRowSpan); + Vector4Utils.Premultiply(tempRowSpan); ref Vector4 firstPassBaseRef = ref firstPassPixelsTransposed.Span[y]; if (this.Compand) { - Vector4Extensions.Expand(tempRowSpan); + SRgbCompanding.Expand(tempRowSpan); } for (int x = minX; x < maxX; x++) @@ -300,11 +301,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms Unsafe.Add(ref tempRowBase, x) = window.Convolve(firstPassColumn, sourceY); } - Vector4Extensions.UnPremultiply(tempRowSpan); + Vector4Utils.UnPremultiply(tempRowSpan); if (this.Compand) { - Vector4Extensions.Compress(tempRowSpan); + SRgbCompanding.Compress(tempRowSpan); } Span targetRowSpan = destination.GetPixelRowSpan(y); diff --git a/tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs b/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs similarity index 59% rename from tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs rename to tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs index 125f8f9941..91cacfe3f0 100644 --- a/tests/ImageSharp.Tests/Colorspaces/Conversion/CompandingTests.cs +++ b/tests/ImageSharp.Tests/Colorspaces/Companding/CompandingTests.cs @@ -1,10 +1,13 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; +using System; +using System.Linq; +using System.Numerics; +using SixLabors.ImageSharp.ColorSpaces.Companding; using Xunit; -namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion +namespace SixLabors.ImageSharp.Tests.Colorspaces.Companding { /// /// Tests various companding algorithms. Numbers are hand calculated from formulas online. @@ -16,7 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion private static readonly ApproximateFloatComparer FloatComparer = new ApproximateFloatComparer(.00001F); [Fact] - public void Rec2020CompandingIsCorrect() + public void Rec2020Companding_IsCorrect() { const float input = .667F; float e = Rec2020Companding.Expand(input); @@ -25,7 +28,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } [Fact] - public void Rec709CompandingIsCorrect() + public void Rec709Companding_IsCorrect() { const float input = .667F; float e = Rec709Companding.Expand(input); @@ -34,7 +37,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } [Fact] - public void SRgbCompandingIsCorrect() + public void SRgbCompanding_IsCorrect() { const float input = .667F; float e = SRgbCompanding.Expand(input); @@ -42,8 +45,38 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion CompandingIsCorrectImpl(e, c, .40242353F, .667F); } + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void SRgbCompanding_Expand_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => SRgbCompanding.Expand(v)).ToArray(); + + SRgbCompanding.Expand(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void SRgbCompanding_Compress_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => SRgbCompanding.Compress(v)).ToArray(); + + SRgbCompanding.Compress(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + [Fact] - public void GammaCompandingIsCorrect() + public void GammaCompanding_IsCorrect() { const float gamma = 2.2F; const float input = .667F; @@ -53,7 +86,7 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion } [Fact] - public void LCompandingIsCorrect() + public void LCompanding_IsCorrect() { const float input = .667F; float e = LCompanding.Expand(input); @@ -67,4 +100,4 @@ namespace SixLabors.ImageSharp.Tests.Colorspaces.Conversion Assert.Equal(compressed, c, FloatComparer); } } -} +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs b/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs deleted file mode 100644 index 2d2a2795d8..0000000000 --- a/tests/ImageSharp.Tests/Helpers/Vector4ExtensionsTests.cs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright (c) Six Labors and contributors. -// Licensed under the Apache License, Version 2.0. - -using System; -using System.Linq; -using System.Numerics; - -using Xunit; - -namespace SixLabors.ImageSharp.Tests.Helpers -{ - public class Vector4ExtensionsTests - { - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void Premultiply_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => v.Premultiply()).ToArray(); - - Vector4Extensions.Premultiply(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } - - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void UnPremultiply_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => v.UnPremultiply()).ToArray(); - - Vector4Extensions.UnPremultiply(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } - - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void Expand_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => v.Expand()).ToArray(); - - Vector4Extensions.Expand(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } - - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(30)] - public void Compress_VectorSpan(int length) - { - var rnd = new Random(42); - Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => v.Compress()).ToArray(); - - Vector4Extensions.Compress(source); - - Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); - } - } -} diff --git a/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs new file mode 100644 index 0000000000..d2e1ddf4e2 --- /dev/null +++ b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs @@ -0,0 +1,44 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Linq; +using System.Numerics; + +using Xunit; + +namespace SixLabors.ImageSharp.Tests.Helpers +{ + public class Vector4UtilsTests + { + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void Premultiply_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => Vector4Utils.Premultiply(v)).ToArray(); + + Vector4Utils.Premultiply(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + + [Theory] + [InlineData(0)] + [InlineData(1)] + [InlineData(30)] + public void UnPremultiply_VectorSpan(int length) + { + var rnd = new Random(42); + Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); + Vector4[] expected = source.Select(v => Vector4Utils.UnPremultiply(v)).ToArray(); + + Vector4Utils.UnPremultiply(source); + + Assert.Equal(expected, source, new ApproximateFloatComparer(1e-6f)); + } + } +} From 400a3cbe89abd1f9726022243c405f1fb2d11751 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 12 Oct 2018 12:36:55 +0100 Subject: [PATCH 170/185] Refactor Vector4Utils and ConvolutionProcessors utilizing them. --- .../Common/Helpers/DenseMatrixUtils.cs | 131 ++++++++++++++++++ src/ImageSharp/Common/Helpers/Vector4Utils.cs | 34 ++--- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 10 +- .../Convolution/Convolution2DProcessor.cs | 90 +++--------- .../Convolution/Convolution2PassProcessor.cs | 56 +++----- .../Convolution/ConvolutionProcessor.cs | 75 +++------- .../Transforms/AffineTransformProcessor.cs | 7 +- .../ProjectiveTransformProcessor.cs | 7 +- .../General/Vectorization/Premultiply.cs | 59 ++++++++ .../Helpers/Vector4UtilsTests.cs | 4 +- 10 files changed, 279 insertions(+), 194 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs create mode 100644 tests/ImageSharp.Benchmarks/General/Vectorization/Premultiply.cs diff --git a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs new file mode 100644 index 0000000000..0755ae8a1a --- /dev/null +++ b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs @@ -0,0 +1,131 @@ +// Copyright (c) Six Labors and contributors. +// Licensed under the Apache License, Version 2.0. + +using System; +using System.Numerics; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Primitives; + +namespace SixLabors.ImageSharp +{ + /// + /// Extension methods for . + /// + internal static class DenseMatrixUtils + { + /// + /// Computes the sum of vectors in weighted by the kernel weight values. + /// + /// The pixel format. + /// The dense matrix. + /// The source frame. + /// The target row. + /// The current row. + /// The current column. + /// The maximum working area row. + /// The maximum working area column. + /// The column offset to apply to source sampling. + public static void Convolve( + in DenseMatrix matrix, + Buffer2D sourcePixels, + Span targetRow, + int row, + int column, + int maxRow, + int maxColumn, + int offsetColumn) + where TPixel : struct, IPixel + { + Vector4 vector = default; + int matrixHeight = matrix.Rows; + int matrixWidth = matrix.Columns; + int radiusY = matrixHeight >> 1; + int radiusX = matrixWidth >> 1; + + for (int y = 0; y < matrixHeight; y++) + { + int offsetY = (row + y - radiusY).Clamp(0, maxRow); + Span sourceRowSpan = sourcePixels.GetRowSpan(offsetY); + + for (int x = 0; x < matrixWidth; x++) + { + int offsetX = (column + offsetColumn + x - radiusX).Clamp(offsetColumn, maxColumn); + var currentColor = sourceRowSpan[offsetX].ToVector4(); + Vector4Utils.Premultiply(ref currentColor); + currentColor *= matrix[y, x]; + vector += currentColor; + } + } + + ref Vector4 target = ref targetRow[column]; + vector.W = target.W; + Vector4Utils.UnPremultiply(ref vector); + target = vector; + } + + /// + /// Computes the sum of vectors in weighted by the two kernel weight values. + /// + /// The pixel format. + /// The vertical dense matrix. + /// The horizontal dense matrix. + /// The source frame. + /// The target row. + /// The current row. + /// The current column. + /// The maximum working area row. + /// The maximum working area column. + /// The column offset to apply to source sampling. + public static void Convolve2D( + in DenseMatrix matrixY, + in DenseMatrix matrixX, + Buffer2D sourcePixels, + Span targetRow, + int row, + int column, + int maxRow, + int maxColumn, + int offsetColumn) + where TPixel : struct, IPixel + { + Vector4 vectorY = default; + Vector4 vectorX = default; + int matrixYHeight = matrixY.Rows; + int matrixYWidth = matrixY.Columns; + int matrixXHeight = matrixX.Rows; + int matrixXWidth = matrixX.Columns; + int radiusY = matrixYHeight >> 1; + int radiusX = matrixXWidth >> 1; + + for (int y = 0; y < matrixYHeight; y++) + { + int offsetY = (row + y - radiusY).Clamp(0, maxRow); + Span sourceRowSpan = sourcePixels.GetRowSpan(offsetY); + + for (int x = 0; x < matrixXWidth; x++) + { + int offsetX = (column + offsetColumn + x - radiusX).Clamp(offsetColumn, maxColumn); + var currentColor = sourceRowSpan[offsetX].ToVector4(); + Vector4Utils.Premultiply(ref currentColor); + + if (y < matrixXHeight) + { + vectorX += matrixX[y, x] * currentColor; + } + + if (x < matrixYWidth) + { + vectorY += matrixY[y, x] * currentColor; + } + } + } + + var vector = Vector4.SquareRoot((vectorX * vectorX) + (vectorY * vectorY)); + ref Vector4 target = ref targetRow[column]; + vector.W = target.W; + Vector4Utils.UnPremultiply(ref vector); + target = vector; + } + } +} \ No newline at end of file diff --git a/src/ImageSharp/Common/Helpers/Vector4Utils.cs b/src/ImageSharp/Common/Helpers/Vector4Utils.cs index 4545d797c2..75bb00b6a5 100644 --- a/src/ImageSharp/Common/Helpers/Vector4Utils.cs +++ b/src/ImageSharp/Common/Helpers/Vector4Utils.cs @@ -17,32 +17,28 @@ namespace SixLabors.ImageSharp /// Pre-multiplies the "x", "y", "z" components of a vector by its "w" component leaving the "w" component intact. /// /// The to premultiply - /// The [MethodImpl(InliningOptions.ShortMethod)] - public static Vector4 Premultiply(Vector4 source) + public static void Premultiply(ref Vector4 source) { float w = source.W; - Vector4 premultiplied = source * w; - premultiplied.W = w; - return premultiplied; + source *= w; + source.W = w; } /// - /// Reverses the result of premultiplying a vector via . + /// Reverses the result of premultiplying a vector via . /// /// The to premultiply - /// The [MethodImpl(InliningOptions.ShortMethod)] - public static Vector4 UnPremultiply(Vector4 source) + public static void UnPremultiply(ref Vector4 source) { float w = source.W; - Vector4 unpremultiplied = source / w; - unpremultiplied.W = w; - return unpremultiplied; + source /= w; + source.W = w; } /// - /// Bulk variant of + /// Bulk variant of /// /// The span of vectors [MethodImpl(InliningOptions.ShortMethod)] @@ -54,16 +50,12 @@ namespace SixLabors.ImageSharp for (int i = 0; i < vectors.Length; i++) { ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - var s = new Vector4(v.W) - { - W = 1 - }; - v *= s; + Premultiply(ref v); } } /// - /// Bulk variant of + /// Bulk variant of /// /// The span of vectors [MethodImpl(InliningOptions.ShortMethod)] @@ -75,11 +67,7 @@ namespace SixLabors.ImageSharp for (int i = 0; i < vectors.Length; i++) { ref Vector4 v = ref Unsafe.Add(ref baseRef, i); - var s = new Vector4(1 / v.W) - { - W = 1 - }; - v *= s; + UnPremultiply(ref v); } } } diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index ef1abc8971..2a4b9dc07f 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -182,13 +182,13 @@ namespace SixLabors.ImageSharp.Primitives } /// - public bool Equals(DenseMatrix other) => - this.Columns == other.Columns && - this.Rows == other.Rows && - this.Span.SequenceEqual(other.Span); + public override bool Equals(object obj) => obj is DenseMatrix other && this.Equals(other); /// - public override bool Equals(object obj) => obj is DenseMatrix other && this.Equals(other); + public bool Equals(DenseMatrix other) => + this.Columns == other.Columns + && this.Rows == other.Rows + && this.Span.SequenceEqual(other.Span); /// public override int GetHashCode() => this.Data.GetHashCode(); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index c358b316c1..1ecf9b7598 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -3,8 +3,6 @@ using System; using System.Numerics; - -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; @@ -47,89 +45,43 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Rectangle sourceRectangle, Configuration configuration) { - int kernelYHeight = this.KernelY.Rows; - int kernelYWidth = this.KernelY.Columns; - int kernelXHeight = this.KernelX.Rows; - int kernelXWidth = this.KernelX.Columns; - int radiusY = kernelYHeight >> 1; - int radiusX = kernelXWidth >> 1; - - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; + DenseMatrix matrixY = this.KernelY; + DenseMatrix matrixX = this.KernelX; + + var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + int startY = interest.Y; + int endY = interest.Bottom; + int startX = interest.X; + int endX = interest.Right; int maxY = endY - 1; int maxX = endX - 1; - using (Buffer2D targetPixels = - configuration.MemoryAllocator.Allocate2D(source.Width, source.Height)) + using (Buffer2D targetPixels = configuration.MemoryAllocator.Allocate2D(source.Width, source.Height)) { source.CopyTo(targetPixels); var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); + int width = workingRectangle.Width; - ParallelHelper.IterateRows( + ParallelHelper.IterateRowsWithTempBuffer( workingRectangle, configuration, - rows => + (rows, vectorBuffer) => { + Span vectorSpan = vectorBuffer.Span; + int length = vectorSpan.Length; + for (int y = rows.Min; y < rows.Max; y++) { - Span sourceRow = source.GetPixelRowSpan(y); - Span targetRow = targetPixels.GetRowSpan(y); + Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); + PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); - for (int x = startX; x < endX; x++) + for (int x = 0; x < width; x++) { - float rX = 0; - float gX = 0; - float bX = 0; - float rY = 0; - float gY = 0; - float bY = 0; - - // Apply each matrix multiplier to the color components for each pixel. - for (int fy = 0; fy < kernelYHeight; fy++) - { - int fyr = fy - radiusY; - int offsetY = y + fyr; - - offsetY = offsetY.Clamp(0, maxY); - Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); - - for (int fx = 0; fx < kernelXWidth; fx++) - { - int fxr = fx - radiusX; - int offsetX = x + fxr; - - offsetX = offsetX.Clamp(0, maxX); - Vector4 currentColor = Vector4Utils.Premultiply(sourceOffsetRow[offsetX].ToVector4()); - - if (fy < kernelXHeight) - { - Vector4 kx = this.KernelX[fy, fx] * currentColor; - rX += kx.X; - gX += kx.Y; - bX += kx.Z; - } - - if (fx < kernelYWidth) - { - Vector4 ky = this.KernelY[fy, fx] * currentColor; - rY += ky.X; - gY += ky.Y; - bY += ky.Z; - } - } - } - - float red = MathF.Sqrt((rX * rX) + (rY * rY)); - float green = MathF.Sqrt((gX * gX) + (gY * gY)); - float blue = MathF.Sqrt((bX * bX) + (bY * bY)); - - ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4( - Vector4Utils.UnPremultiply(new Vector4(red, green, blue, sourceRow[x].ToVector4().W))); + DenseMatrixUtils.Convolve2D(in matrixY, in matrixX, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } + + PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); } }); diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs index 3135ff6148..1f47649e6f 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2PassProcessor.cs @@ -45,8 +45,11 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { using (Buffer2D firstPassPixels = configuration.MemoryAllocator.Allocate2D(source.Size())) { - this.ApplyConvolution(firstPassPixels, source.PixelBuffer, source.Bounds(), this.KernelX, configuration); - this.ApplyConvolution(source.PixelBuffer, firstPassPixels, sourceRectangle, this.KernelY, configuration); + source.CopyTo(firstPassPixels); + + var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + this.ApplyConvolution(firstPassPixels, source.PixelBuffer, interest, this.KernelX, configuration); + this.ApplyConvolution(source.PixelBuffer, firstPassPixels, interest, this.KernelY, configuration); } } @@ -65,14 +68,10 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution Buffer2D targetPixels, Buffer2D sourcePixels, Rectangle sourceRectangle, - DenseMatrix kernel, // TODO: Can't use 'in' as pass by ref to lambda expression. + in DenseMatrix kernel, Configuration configuration) { - int kernelHeight = kernel.Rows; - int kernelWidth = kernel.Columns; - int radiusY = kernelHeight >> 1; - int radiusX = kernelWidth >> 1; - + DenseMatrix matrix = kernel; int startY = sourceRectangle.Y; int endY = sourceRectangle.Bottom; int startX = sourceRectangle.X; @@ -81,44 +80,27 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution int maxX = endX - 1; var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); + int width = workingRectangle.Width; - ParallelHelper.IterateRows( + ParallelHelper.IterateRowsWithTempBuffer( workingRectangle, configuration, - rows => + (rows, vectorBuffer) => { + Span vectorSpan = vectorBuffer.Span; + int length = vectorSpan.Length; + for (int y = rows.Min; y < rows.Max; y++) { - Span targetRow = targetPixels.GetRowSpan(y); + Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); + PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); - for (int x = startX; x < endX; x++) + for (int x = 0; x < width; x++) { - Vector4 destination = default; - - // Apply each matrix multiplier to the color components for each pixel. - for (int fy = 0; fy < kernelHeight; fy++) - { - int fyr = fy - radiusY; - int offsetY = y + fyr; - - offsetY = offsetY.Clamp(0, maxY); - Span row = sourcePixels.GetRowSpan(offsetY); - - for (int fx = 0; fx < kernelWidth; fx++) - { - int fxr = fx - radiusX; - int offsetX = x + fxr; - - offsetX = offsetX.Clamp(0, maxX); - - Vector4 currentColor = Vector4Utils.Premultiply(row[offsetX].ToVector4()); - destination += kernel[fy, fx] * currentColor; - } - } - - ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4(Vector4Utils.UnPremultiply(destination)); + DenseMatrixUtils.Convolve(in matrix, sourcePixels, vectorSpan, y, x, maxY, maxX, startX); } + + PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); } }); } diff --git a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs index 1d1755ccd6..d2f3f8fc58 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/ConvolutionProcessor.cs @@ -3,14 +3,10 @@ using System; using System.Numerics; -using System.Threading.Tasks; -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.ParallelUtils; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Primitives; -using SixLabors.ImageSharp.Processing.Processors; -using SixLabors.Memory; using SixLabors.Primitives; namespace SixLabors.ImageSharp.Processing.Processors.Convolution @@ -26,10 +22,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// Initializes a new instance of the class. /// /// The 2d gradient operator. - public ConvolutionProcessor(DenseMatrix kernelXY) - { - this.KernelXY = kernelXY; - } + public ConvolutionProcessor(DenseMatrix kernelXY) => this.KernelXY = kernelXY; /// /// Gets the 2d gradient operator. @@ -39,13 +32,12 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) { - int kernelLength = this.KernelXY.Rows; - int radius = kernelLength >> 1; - - int startY = sourceRectangle.Y; - int endY = sourceRectangle.Bottom; - int startX = sourceRectangle.X; - int endX = sourceRectangle.Right; + DenseMatrix matrix = this.KernelXY; + var interest = Rectangle.Intersect(sourceRectangle, source.Bounds()); + int startY = interest.Y; + int endY = interest.Bottom; + int startX = interest.X; + int endX = interest.Right; int maxY = endY - 1; int maxX = endX - 1; @@ -53,53 +45,28 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution { source.CopyTo(targetPixels); - var workingRect = Rectangle.FromLTRB(startX, startY, endX, endY); + var workingRectangle = Rectangle.FromLTRB(startX, startY, endX, endY); + int width = workingRectangle.Width; - ParallelHelper.IterateRows( - workingRect, + ParallelHelper.IterateRowsWithTempBuffer( + workingRectangle, configuration, - rows => + (rows, vectorBuffer) => { + Span vectorSpan = vectorBuffer.Span; + int length = vectorSpan.Length; + for (int y = rows.Min; y < rows.Max; y++) { - Span sourceRow = source.GetPixelRowSpan(y); - Span targetRow = targetPixels.GetRowSpan(y); + Span targetRowSpan = targetPixels.GetRowSpan(y).Slice(startX); + PixelOperations.Instance.ToVector4(targetRowSpan, vectorSpan, length); - for (int x = startX; x < endX; x++) + for (int x = 0; x < width; x++) { - float red = 0; - float green = 0; - float blue = 0; - - // Apply each matrix multiplier to the color components for each pixel. - for (int fy = 0; fy < kernelLength; fy++) - { - int fyr = fy - radius; - int offsetY = y + fyr; - - offsetY = offsetY.Clamp(0, maxY); - Span sourceOffsetRow = source.GetPixelRowSpan(offsetY); - - for (int fx = 0; fx < kernelLength; fx++) - { - int fxr = fx - radius; - int offsetX = x + fxr; - - offsetX = offsetX.Clamp(0, maxX); - - Vector4 currentColor = Vector4Utils.Premultiply(sourceOffsetRow[offsetX].ToVector4()); - currentColor *= this.KernelXY[fy, fx]; - - red += currentColor.X; - green += currentColor.Y; - blue += currentColor.Z; - } - } - - ref TPixel pixel = ref targetRow[x]; - pixel.PackFromVector4( - Vector4Utils.UnPremultiply(new Vector4(red, green, blue, sourceRow[x].ToVector4().W))); + DenseMatrixUtils.Convolve(in matrix, source.PixelBuffer, vectorSpan, y, x, maxY, maxX, startX); } + + PixelOperations.Instance.PackFromVector4(vectorSpan, targetRowSpan, length); } }); diff --git a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs index 225c687d87..790eb80482 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/AffineTransformProcessor.cs @@ -208,14 +208,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float xWeight = Unsafe.Add(ref xSpanRef, xx); // Values are first premultiplied to prevent darkening of edge pixels - sum += Vector4Utils.Premultiply(source[i, j].ToVector4()) * xWeight * yWeight; + var current = source[i, j].ToVector4(); + Vector4Utils.Premultiply(ref current); + sum += current * xWeight * yWeight; } } ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); // Reverse the premultiplication - dest.PackFromVector4(Vector4Utils.UnPremultiply(sum)); + Vector4Utils.UnPremultiply(ref sum); + dest.PackFromVector4(sum); } } }); diff --git a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs index f860264af5..bad8eab3af 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/ProjectiveTransformProcessor.cs @@ -217,14 +217,17 @@ namespace SixLabors.ImageSharp.Processing.Processors.Transforms float xWeight = Unsafe.Add(ref xSpanRef, xx); // Values are first premultiplied to prevent darkening of edge pixels - sum += Vector4Utils.Premultiply(source[i, j].ToVector4()) * xWeight * yWeight; + var current = source[i, j].ToVector4(); + Vector4Utils.Premultiply(ref current); + sum += current * xWeight * yWeight; } } ref TPixel dest = ref Unsafe.Add(ref destRowRef, x); // Reverse the premultiplication - dest.PackFromVector4(Vector4Utils.UnPremultiply(sum)); + Vector4Utils.UnPremultiply(ref sum); + dest.PackFromVector4(sum); } } }); diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/Premultiply.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/Premultiply.cs new file mode 100644 index 0000000000..23f13c89b7 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/Premultiply.cs @@ -0,0 +1,59 @@ +using System.Numerics; +using System.Runtime.CompilerServices; +using BenchmarkDotNet.Attributes; + +namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization +{ + public class Premultiply + { + [Benchmark(Baseline = true)] + public Vector4 PremultiplyByVal() + { + var input = new Vector4(.5F); + return Vector4Utils.Premultiply(input); + } + + [Benchmark] + public Vector4 PremultiplyByRef() + { + var input = new Vector4(.5F); + Vector4Utils.PremultiplyRef(ref input); + return input; + } + + [Benchmark] + public Vector4 PremultiplyRefWithPropertyAssign() + { + var input = new Vector4(.5F); + Vector4Utils.PremultiplyRefWithPropertyAssign(ref input); + return input; + } + } + + internal static class Vector4Utils + { + [MethodImpl(InliningOptions.ShortMethod)] + public static Vector4 Premultiply(Vector4 source) + { + float w = source.W; + Vector4 premultiplied = source * w; + premultiplied.W = w; + return premultiplied; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public static void PremultiplyRef(ref Vector4 source) + { + float w = source.W; + source *= w; + source.W = w; + } + + [MethodImpl(InliningOptions.ShortMethod)] + public static void PremultiplyRefWithPropertyAssign(ref Vector4 source) + { + float w = source.W; + source *= new Vector4(w) { W = 1 }; + } + } +} \ No newline at end of file diff --git a/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs index d2e1ddf4e2..9416be740a 100644 --- a/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs +++ b/tests/ImageSharp.Tests/Helpers/Vector4UtilsTests.cs @@ -19,7 +19,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers { var rnd = new Random(42); Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => Vector4Utils.Premultiply(v)).ToArray(); + Vector4[] expected = source.Select(v => { Vector4Utils.Premultiply(ref v); return v; }).ToArray(); Vector4Utils.Premultiply(source); @@ -34,7 +34,7 @@ namespace SixLabors.ImageSharp.Tests.Helpers { var rnd = new Random(42); Vector4[] source = rnd.GenerateRandomVectorArray(length, 0, 1); - Vector4[] expected = source.Select(v => Vector4Utils.UnPremultiply(v)).ToArray(); + Vector4[] expected = source.Select(v => { Vector4Utils.UnPremultiply(ref v); return v; }).ToArray(); Vector4Utils.UnPremultiply(source); From 5db580ffcc1b157578588a9441291541515bea84 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 12 Oct 2018 13:19:51 +0100 Subject: [PATCH 171/185] Update tests/Images/External --- tests/Images/External | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/Images/External b/tests/Images/External index 03c7fa7582..ee90e5f322 160000 --- a/tests/Images/External +++ b/tests/Images/External @@ -1 +1 @@ -Subproject commit 03c7fa7582dea75cea0d49514ccb7e1b6dc9e780 +Subproject commit ee90e5f32218027744b5d40058b587cc1047b76f From 9fd210926853bcbf65c0542726b8e6ca177ff70a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 12 Oct 2018 13:58:51 +0100 Subject: [PATCH 172/185] Update test to match new reference naming. --- .../ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs index 3522ade7c4..d65796d37f 100644 --- a/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs +++ b/tests/ImageSharp.Tests/Drawing/FillLinearGradientBrushTests.cs @@ -319,13 +319,14 @@ namespace SixLabors.ImageSharp.Tests.Drawing var coloringVariant = new StringBuilder(); ColorStop[] colorStops = new ColorStop[stopPositions.Length]; + Rgba32 rgba = default; for (int i = 0; i < stopPositions.Length; i++) { TPixel color = colors[stopColorCodes[i % colors.Length]]; float position = stopPositions[i]; - + color.ToRgba32(ref rgba); colorStops[i] = new ColorStop(position, color); - coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", color, position); + coloringVariant.AppendFormat(CultureInfo.InvariantCulture, "{0}@{1};", rgba.ToHex(), position); } FormattableString variant = $"({startX},{startY})_TO_({endX},{endY})__[{coloringVariant}]"; From ba93355937eaab8d3cc2cda97d59776161770a67 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 12 Oct 2018 22:21:23 +0100 Subject: [PATCH 173/185] Remove conditionals from loop and enforce equal matrice dimensions. --- .../Common/Helpers/DenseMatrixUtils.cs | 35 ++++++++----------- src/ImageSharp/Primitives/DenseMatrix{T}.cs | 8 +++++ .../Convolution/Convolution2DProcessor.cs | 1 + .../Convolution/EdgeDetector2DProcessor.cs | 6 ++-- .../Primitives/DenseMatrixTests.cs | 2 ++ 5 files changed, 27 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs index 0755ae8a1a..2e700c9d67 100644 --- a/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs +++ b/src/ImageSharp/Common/Helpers/DenseMatrixUtils.cs @@ -42,6 +42,7 @@ namespace SixLabors.ImageSharp int matrixWidth = matrix.Columns; int radiusY = matrixHeight >> 1; int radiusX = matrixWidth >> 1; + int sourceOffsetColumnBase = column + offsetColumn; for (int y = 0; y < matrixHeight; y++) { @@ -50,11 +51,11 @@ namespace SixLabors.ImageSharp for (int x = 0; x < matrixWidth; x++) { - int offsetX = (column + offsetColumn + x - radiusX).Clamp(offsetColumn, maxColumn); + int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(offsetColumn, maxColumn); var currentColor = sourceRowSpan[offsetX].ToVector4(); Vector4Utils.Premultiply(ref currentColor); - currentColor *= matrix[y, x]; - vector += currentColor; + + vector += matrix[y, x] * currentColor; } } @@ -91,33 +92,25 @@ namespace SixLabors.ImageSharp { Vector4 vectorY = default; Vector4 vectorX = default; - int matrixYHeight = matrixY.Rows; - int matrixYWidth = matrixY.Columns; - int matrixXHeight = matrixX.Rows; - int matrixXWidth = matrixX.Columns; - int radiusY = matrixYHeight >> 1; - int radiusX = matrixXWidth >> 1; + int matrixHeight = matrixY.Rows; + int matrixWidth = matrixY.Columns; + int radiusY = matrixHeight >> 1; + int radiusX = matrixWidth >> 1; + int sourceOffsetColumnBase = column + offsetColumn; - for (int y = 0; y < matrixYHeight; y++) + for (int y = 0; y < matrixHeight; y++) { int offsetY = (row + y - radiusY).Clamp(0, maxRow); Span sourceRowSpan = sourcePixels.GetRowSpan(offsetY); - for (int x = 0; x < matrixXWidth; x++) + for (int x = 0; x < matrixWidth; x++) { - int offsetX = (column + offsetColumn + x - radiusX).Clamp(offsetColumn, maxColumn); + int offsetX = (sourceOffsetColumnBase + x - radiusX).Clamp(offsetColumn, maxColumn); var currentColor = sourceRowSpan[offsetX].ToVector4(); Vector4Utils.Premultiply(ref currentColor); - if (y < matrixXHeight) - { - vectorX += matrixX[y, x] * currentColor; - } - - if (x < matrixYWidth) - { - vectorY += matrixY[y, x] * currentColor; - } + vectorX += matrixX[y, x] * currentColor; + vectorY += matrixY[y, x] * currentColor; } } diff --git a/src/ImageSharp/Primitives/DenseMatrix{T}.cs b/src/ImageSharp/Primitives/DenseMatrix{T}.cs index 2a4b9dc07f..7cfa98ec1b 100644 --- a/src/ImageSharp/Primitives/DenseMatrix{T}.cs +++ b/src/ImageSharp/Primitives/DenseMatrix{T}.cs @@ -4,6 +4,7 @@ using System; using System.Diagnostics; using System.Runtime.CompilerServices; +using SixLabors.Primitives; namespace SixLabors.ImageSharp.Primitives { @@ -31,6 +32,11 @@ namespace SixLabors.ImageSharp.Primitives /// public readonly int Rows; + /// + /// Gets the size of the dense matrix. + /// + public readonly Size Size; + /// /// Gets the number of items in the array. /// @@ -57,6 +63,7 @@ namespace SixLabors.ImageSharp.Primitives this.Rows = rows; this.Columns = columns; + this.Size = new Size(columns, rows); this.Count = columns * rows; this.Data = new T[this.Columns * this.Rows]; } @@ -76,6 +83,7 @@ namespace SixLabors.ImageSharp.Primitives this.Rows = rows; this.Columns = columns; + this.Size = new Size(columns, rows); this.Count = this.Columns * this.Rows; this.Data = new T[this.Columns * this.Rows]; diff --git a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs index 1ecf9b7598..0669a12470 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/Convolution2DProcessor.cs @@ -25,6 +25,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// The vertical gradient operator. public Convolution2DProcessor(DenseMatrix kernelX, DenseMatrix kernelY) { + Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same."); this.KernelX = kernelX; this.KernelY = kernelY; } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs index dd43d3e159..8927716492 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetector2DProcessor.cs @@ -23,6 +23,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution /// Whether to convert the image to grayscale before performing edge detection. protected EdgeDetector2DProcessor(DenseMatrix kernelX, DenseMatrix kernelY, bool grayscale) { + Guard.IsTrue(kernelX.Size.Equals(kernelY.Size), $"{nameof(kernelX)} {nameof(kernelY)}", "Kernel sizes must be the same."); this.KernelX = kernelX; this.KernelY = kernelY; this.Grayscale = grayscale; @@ -42,10 +43,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Convolution public bool Grayscale { get; set; } /// - protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) - { - new Convolution2DProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); - } + protected override void OnFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) => new Convolution2DProcessor(this.KernelX, this.KernelY).Apply(source, sourceRectangle, configuration); /// protected override void BeforeFrameApply(ImageFrame source, Rectangle sourceRectangle, Configuration configuration) diff --git a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs b/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs index 7d161d35f7..fa4862293f 100644 --- a/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs +++ b/tests/ImageSharp.Tests/Primitives/DenseMatrixTests.cs @@ -3,6 +3,7 @@ using System; using SixLabors.ImageSharp.Primitives; +using SixLabors.Primitives; using Xunit; namespace SixLabors.ImageSharp.Tests.Primitives @@ -59,6 +60,7 @@ namespace SixLabors.ImageSharp.Tests.Primitives Assert.True(dense.Rows == FloydSteinbergMatrix.GetLength(0)); Assert.Equal(3, dense.Columns); Assert.Equal(2, dense.Rows); + Assert.Equal(new Size(3, 2), dense.Size); } [Fact] From 0d39a0343a2b9639b8161f6a2b3f066c01dc2064 Mon Sep 17 00:00:00 2001 From: j0rn Date: Mon, 15 Oct 2018 13:03:08 +0200 Subject: [PATCH 174/185] Write float values using the invariant culture. --- src/ImageSharp/ColorSpaces/CieLab.cs | 3 ++- src/ImageSharp/ColorSpaces/CieLch.cs | 3 ++- src/ImageSharp/ColorSpaces/CieLchuv.cs | 3 ++- src/ImageSharp/ColorSpaces/CieLuv.cs | 3 ++- .../ColorSpaces/CieXyChromaticityCoordinates.cs | 3 ++- src/ImageSharp/ColorSpaces/CieXyy.cs | 3 ++- src/ImageSharp/ColorSpaces/CieXyz.cs | 3 ++- src/ImageSharp/ColorSpaces/Cmyk.cs | 3 ++- src/ImageSharp/ColorSpaces/Hsl.cs | 3 ++- src/ImageSharp/ColorSpaces/Hsv.cs | 3 ++- src/ImageSharp/ColorSpaces/HunterLab.cs | 3 ++- src/ImageSharp/ColorSpaces/LinearRgb.cs | 3 ++- src/ImageSharp/ColorSpaces/Lms.cs | 3 ++- src/ImageSharp/ColorSpaces/Rgb.cs | 3 ++- src/ImageSharp/ColorSpaces/YCbCr.cs | 3 ++- src/ImageSharp/Common/Helpers/FloatToStringUtil.cs | 11 +++++++++++ 16 files changed, 41 insertions(+), 15 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/FloatToStringUtil.cs diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index 230ea0bdc3..d7af041204 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -127,7 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"; + public override string ToString() => $"CieLab({FloatToString(this.L, this.A, this.B)})"; /// public override bool Equals(object obj) => obj is CieLab other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index 2c8f030e24..b0192b214f 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -129,7 +130,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"; + public override string ToString() => $"CieLch({FloatToString(this.L, this.C, this.H)})"; /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index 2aaff48a09..3e0d654dd7 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -128,7 +129,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"; + public override string ToString() => $"CieLchuv({FloatToString(this.L, this.C, this.H)})"; /// public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index 9aac268e1c..e0c17224da 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -128,7 +129,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})"; + public override string ToString() => $"CieLuv({FloatToString(this.L, this.U, this.V)})"; /// public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs index 06aaafb553..e29411f670 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs @@ -3,6 +3,7 @@ using System; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; // ReSharper disable CompareOfFloatsByEqualityOperator namespace SixLabors.ImageSharp.ColorSpaces @@ -67,7 +68,7 @@ namespace SixLabors.ImageSharp.ColorSpaces public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode()); /// - public override string ToString() => $"CieXyChromaticityCoordinates({this.X:#0.##}, {this.Y:#0.##})"; + public override string ToString() => $"CieXyChromaticityCoordinates({FloatToString(this.X, this.Y)})"; /// public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index 44696a9dba..a036e89c3e 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -91,7 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})"; + public override string ToString() => $"CieXyy({FloatToString(this.X, this.Y, this.Yl)})"; /// public override bool Equals(object obj) => obj is CieXyy other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index 4fed9f4eda..f6d6e285e9 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -94,7 +95,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})"; + public override string ToString() => $"CieXyz({FloatToString(this.X, this.Y, this.Z)})"; /// public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index 1d64e19951..e351642de5 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -99,7 +100,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})"; + public override string ToString() => $"Cmyk({FloatToString(this.C, this.M, this.Y, this.K)})"; /// public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index acc735bc53..5684d81840 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -92,7 +93,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})"; + public override string ToString() => $"Hsl({FloatToString(this.H, this.S, this.L)})"; /// public override bool Equals(object obj) => obj is Hsl other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index caabe9b4b6..9d40a6d3fd 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -90,7 +91,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})"; + public override string ToString() => $"Hsv({FloatToString(this.H, this.S, this.V)})"; /// public override bool Equals(object obj) => obj is Hsv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index ed30fa93b2..3e336ca681 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -126,7 +127,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"; + public override string ToString() => $"HunterLab({FloatToString(this.L, this.A, this.B)})"; /// public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index 09a2d83cb3..c376a4d1d4 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -5,6 +5,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -134,7 +135,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"LinearRgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"; + public override string ToString() => $"LinearRgb({FloatToString(this.R, this.G, this.B)})"; /// public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 59a4069b00..823d1c1e1f 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -95,7 +96,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Lms({this.L:#0.##}, {this.M:#0.##}, {this.S:#0.##})"; + public override string ToString() => $"Lms({FloatToString(this.L, this.M, this.S)})"; /// public override bool Equals(object obj) => obj is Lms other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 0700830517..5ccabdfaab 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -6,6 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; using SixLabors.ImageSharp.PixelFormats; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -155,7 +156,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"; + public override string ToString() => $"Rgb({FloatToString(this.R, this.G, this.B)})"; /// public override bool Equals(object obj) => obj is Rgb other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index 7bc59ee767..bbf3f9db22 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -4,6 +4,7 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; +using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -91,7 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"YCbCr({this.Y}, {this.Cb}, {this.Cr})"; + public override string ToString() => $"YCbCr({FloatToString(this.Y, this.Cb, this.Cr)})"; /// public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other); diff --git a/src/ImageSharp/Common/Helpers/FloatToStringUtil.cs b/src/ImageSharp/Common/Helpers/FloatToStringUtil.cs new file mode 100644 index 0000000000..fbb3f8750c --- /dev/null +++ b/src/ImageSharp/Common/Helpers/FloatToStringUtil.cs @@ -0,0 +1,11 @@ +using System.Globalization; +using System.Linq; + +namespace SixLabors.ImageSharp.Common.Helpers +{ + internal static class FloatToStringUtil + { + internal static string FloatToString(params float[] values) + => string.Join(", ", values.Select(v => v.ToString("#0.##", CultureInfo.InvariantCulture)).ToArray()); + } +} From a32b676962be502464e7977f82831ff3985a3363 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 08:52:01 -0700 Subject: [PATCH 175/185] Drop netstandard1.1 support --- .../Common/Extensions/EncoderExtensions.cs | 4 --- src/ImageSharp/Common/Helpers/TestHelpers.cs | 4 +-- src/ImageSharp/Configuration.cs | 8 ------ src/ImageSharp/IO/IFileSystem.cs | 2 -- src/ImageSharp/IO/LocalFileSystem.cs | 17 +++--------- src/ImageSharp/Image.FromBytes.cs | 3 --- src/ImageSharp/Image.FromFile.cs | 4 +-- src/ImageSharp/ImageExtensions.cs | 3 --- src/ImageSharp/ImageSharp.csproj | 4 +-- .../MetaData/Profiles/ICC/IccProfile.cs | 9 +------ .../MetaData/Profiles/ICC/IccWriter.cs | 5 ---- .../MetaData/Profiles/ICC/IccProfileTests.cs | 5 ---- .../TestDataIcc/IccTestDataProfiles.cs | 26 +++---------------- 13 files changed, 12 insertions(+), 82 deletions(-) diff --git a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs index e6b800e86a..82899863c9 100644 --- a/src/ImageSharp/Common/Extensions/EncoderExtensions.cs +++ b/src/ImageSharp/Common/Extensions/EncoderExtensions.cs @@ -20,14 +20,10 @@ namespace SixLabors.ImageSharp /// The string. public static string GetString(this Encoding encoding, ReadOnlySpan buffer) { -#if NETSTANDARD1_1 - return encoding.GetString(buffer.ToArray()); -#else fixed (byte* bytes = buffer) { return encoding.GetString(bytes, buffer.Length); } -#endif } } } diff --git a/src/ImageSharp/Common/Helpers/TestHelpers.cs b/src/ImageSharp/Common/Helpers/TestHelpers.cs index 14e5835b49..45ef7706dd 100644 --- a/src/ImageSharp/Common/Helpers/TestHelpers.cs +++ b/src/ImageSharp/Common/Helpers/TestHelpers.cs @@ -13,9 +13,7 @@ namespace SixLabors.ImageSharp.Common.Helpers /// Only intended to be used in tests! /// internal const string ImageSharpBuiltAgainst = -#if NETSTANDARD1_1 - "netstandard1.1"; -#elif NETCOREAPP2_1 +#if NETCOREAPP2_1 "netcoreapp2.1"; #else "netstandard2.0"; diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 576f7bf3d0..c0064d1877 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -3,15 +3,12 @@ using System; using System.Collections.Generic; -using System.Threading.Tasks; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Formats.Png; -#if !NETSTANDARD1_1 using SixLabors.ImageSharp.IO; -#endif using SixLabors.ImageSharp.Processing; using SixLabors.Memory; @@ -100,12 +97,10 @@ namespace SixLabors.ImageSharp /// internal int MaxHeaderSize => this.ImageFormatsManager.MaxHeaderSize; -#if !NETSTANDARD1_1 /// /// Gets or sets the filesystem helper for accessing the local file system. /// internal IFileSystem FileSystem { get; set; } = new LocalFileSystem(); -#endif /// /// Gets or sets the image operations provider factory. @@ -135,10 +130,7 @@ namespace SixLabors.ImageSharp MemoryAllocator = this.MemoryAllocator, ImageOperationsProvider = this.ImageOperationsProvider, ReadOrigin = this.ReadOrigin, - -#if !NETSTANDARD1_1 FileSystem = this.FileSystem -#endif }; } diff --git a/src/ImageSharp/IO/IFileSystem.cs b/src/ImageSharp/IO/IFileSystem.cs index 088d4abb8b..593c760fcf 100644 --- a/src/ImageSharp/IO/IFileSystem.cs +++ b/src/ImageSharp/IO/IFileSystem.cs @@ -5,7 +5,6 @@ using System.IO; namespace SixLabors.ImageSharp.IO { - #if !NETSTANDARD1_1 /// /// A simple interface representing the filesystem. /// @@ -25,5 +24,4 @@ namespace SixLabors.ImageSharp.IO /// A stream representing the file to open. Stream Create(string path); } -#endif } diff --git a/src/ImageSharp/IO/LocalFileSystem.cs b/src/ImageSharp/IO/LocalFileSystem.cs index 204f5f4e1e..dc5901ff92 100644 --- a/src/ImageSharp/IO/LocalFileSystem.cs +++ b/src/ImageSharp/IO/LocalFileSystem.cs @@ -1,30 +1,19 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; -using System.Collections.Generic; using System.IO; -using System.Text; namespace SixLabors.ImageSharp.IO { - #if !NETSTANDARD1_1 /// /// A wrapper around the local File apis. /// internal class LocalFileSystem : IFileSystem { /// - public Stream OpenRead(string path) - { - return File.OpenRead(path); - } + public Stream OpenRead(string path) => File.OpenRead(path); /// - public Stream Create(string path) - { - return File.Create(path); - } + public Stream Create(string path) => File.Create(path); } -#endif -} +} \ No newline at end of file diff --git a/src/ImageSharp/Image.FromBytes.cs b/src/ImageSharp/Image.FromBytes.cs index 12abf720bd..07adc03ff6 100644 --- a/src/ImageSharp/Image.FromBytes.cs +++ b/src/ImageSharp/Image.FromBytes.cs @@ -174,8 +174,6 @@ namespace SixLabors.ImageSharp } } -#if !NETSTANDARD1_1 - /// /// By reading the header on the provided byte array this calculates the images format. /// @@ -303,6 +301,5 @@ namespace SixLabors.ImageSharp } } } -#endif } } \ No newline at end of file diff --git a/src/ImageSharp/Image.FromFile.cs b/src/ImageSharp/Image.FromFile.cs index ad8f3426f2..b13cef4824 100644 --- a/src/ImageSharp/Image.FromFile.cs +++ b/src/ImageSharp/Image.FromFile.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -#if !NETSTANDARD1_1 using System; using System.IO; using SixLabors.ImageSharp.Formats; @@ -212,5 +211,4 @@ namespace SixLabors.ImageSharp } } } -} -#endif \ No newline at end of file +} \ No newline at end of file diff --git a/src/ImageSharp/ImageExtensions.cs b/src/ImageSharp/ImageExtensions.cs index bf312cb6f5..e579bec1a6 100644 --- a/src/ImageSharp/ImageExtensions.cs +++ b/src/ImageSharp/ImageExtensions.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.IO; -using System.Runtime.InteropServices; using System.Text; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; @@ -17,7 +16,6 @@ namespace SixLabors.ImageSharp /// public static partial class ImageExtensions { -#if !NETSTANDARD1_1 /// /// Writes the image to the given stream using the currently loaded image format. /// @@ -78,7 +76,6 @@ namespace SixLabors.ImageSharp source.Save(fs, encoder); } } -#endif /// /// Writes the image to the given stream using the currently loaded image format. diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index a7ca0a014c..83b2b12604 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -5,7 +5,7 @@ $(packageversion) 0.0.1 Six Labors and contributors - netstandard1.1;netstandard1.3;netstandard2.0;netcoreapp2.1 + netstandard1.3;netstandard2.0;netcoreapp2.1 true true SixLabors.ImageSharp @@ -47,7 +47,7 @@ - + diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs index 44990b7ecc..72665bc69c 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccProfile.cs @@ -3,10 +3,7 @@ using System; using System.Collections.Generic; - -#if !NETSTANDARD1_1 using System.Security.Cryptography; -#endif namespace SixLabors.ImageSharp.MetaData.Profiles.Icc { @@ -100,8 +97,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// public IccProfile DeepClone() => new IccProfile(this); -#if !NETSTANDARD1_1 - /// /// Calculates the MD5 hash value of an ICC profile /// @@ -147,8 +142,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } } -#endif - /// /// Checks for signs of a corrupt profile. /// @@ -227,4 +220,4 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc this.entries = new List(reader.ReadTagData(this.data)); } } -} +} \ No newline at end of file diff --git a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs index c42e32d55a..b476e31955 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/IccWriter.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. -using System; using System.Collections.Generic; using System.Linq; @@ -51,12 +50,8 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc writer.WriteXyzNumber(header.PcsIlluminant); writer.WriteAsciiString(header.CreatorSignature, 4, false); -#if !NETSTANDARD1_1 IccProfileId id = IccProfile.CalculateHash(writer.GetData()); writer.WriteProfileId(id); -#else - writer.WriteProfileId(IccProfileId.Zero); -#endif } private void WriteTagTable(IccDataWriter writer, IccTagTableEntry[] table) diff --git a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccProfileTests.cs b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccProfileTests.cs index 2e2c92182e..17b5dacc4c 100644 --- a/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccProfileTests.cs +++ b/tests/ImageSharp.Tests/MetaData/Profiles/ICC/IccProfileTests.cs @@ -9,9 +9,6 @@ namespace SixLabors.ImageSharp.Tests.Icc { public class IccProfileTests { - -#if !NETSTANDARD1_1 - [Theory] [MemberData(nameof(IccTestDataProfiles.ProfileIdTestData), MemberType = typeof(IccTestDataProfiles))] public void CalculateHash_WithByteArray_CalculatesProfileHash(byte[] data, IccProfileId expected) @@ -33,8 +30,6 @@ namespace SixLabors.ImageSharp.Tests.Icc Assert.Equal(data, copy); } -#endif - [Theory] [MemberData(nameof(IccTestDataProfiles.ProfileValidityTestData), MemberType = typeof(IccTestDataProfiles))] public void CheckIsValid_WithProfiles_ReturnsValidity(byte[] data, bool expected) diff --git a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs index 35ffa2bbb6..b037a7a9af 100644 --- a/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs +++ b/tests/ImageSharp.Tests/TestDataIcc/IccTestDataProfiles.cs @@ -14,20 +14,12 @@ namespace SixLabors.ImageSharp.Tests public static readonly byte[] Header_Random_Id_Array = { -#if !NETSTANDARD1_1 - 0x84, 0xA8, 0xD4, 0x60, 0xC7, 0x16, 0xB6, 0xF3, 0x9B, 0x0E, 0x4C, 0x3D, 0xAB, 0x95, 0xF8, 0x38, -#else - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -#endif + 0x84, 0xA8, 0xD4, 0x60, 0xC7, 0x16, 0xB6, 0xF3, 0x9B, 0x0E, 0x4C, 0x3D, 0xAB, 0x95, 0xF8, 0x38, }; public static readonly byte[] Profile_Random_Id_Array = { -#if !NETSTANDARD1_1 - 0x91, 0x7D, 0x6D, 0xE6, 0x84, 0xC9, 0x58, 0xD1, 0x3B, 0xB0, 0xF5, 0xBB, 0xAD, 0xD1, 0x13, 0x4F, -#else - 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, -#endif + 0x91, 0x7D, 0x6D, 0xE6, 0x84, 0xC9, 0x58, 0xD1, 0x3B, 0xB0, 0xF5, 0xBB, 0xAD, 0xD1, 0x13, 0x4F, }; public static readonly IccProfileHeader Header_Random_Write = CreateHeaderRandomValue( @@ -35,13 +27,7 @@ namespace SixLabors.ImageSharp.Tests new IccProfileId(1, 2, 3, 4), // should be overwritten "ijkl"); // should be overwritten to "acsp" - public static readonly IccProfileHeader Header_Random_Read = CreateHeaderRandomValue(132, -#if !NETSTANDARD1_1 - Header_Random_Id_Value, -#else - IccProfileId.Zero, -#endif - "acsp"); + public static readonly IccProfileHeader Header_Random_Read = CreateHeaderRandomValue(132, Header_Random_Id_Value, "acsp"); public static readonly byte[] Header_Random_Array = CreateHeaderRandomArray(132, 0, Header_Random_Id_Array); @@ -120,11 +106,7 @@ namespace SixLabors.ImageSharp.Tests ); public static readonly IccProfile Profile_Random_Val = new IccProfile(CreateHeaderRandomValue(168, -#if !NETSTANDARD1_1 Profile_Random_Id_Value, -#else - IccProfileId.Zero, -#endif "acsp"), new IccTagDataEntry[] { @@ -239,4 +221,4 @@ namespace SixLabors.ImageSharp.Tests new object[] { Header_Random_Array, true }, }; } -} +} \ No newline at end of file From 9b27fd2fe54cd2a386b1b267ca50c4c4572645e4 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 08:54:58 -0700 Subject: [PATCH 176/185] Use static Encoding.ASCII property --- src/ImageSharp/Formats/Gif/GifConstants.cs | 2 +- src/ImageSharp/Formats/Png/PngConstants.cs | 2 +- .../MetaData/Profiles/ICC/DataReader/IccDataReader.cs | 2 +- .../MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs | 2 +- .../MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs | 2 +- 6 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index 8167d0d2e0..f8942cc3b7 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -104,7 +104,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// Gets the default encoding to use when reading comments. /// - public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); + public static readonly Encoding DefaultEncoding = Encoding.ASCII; /// /// The list of mimetypes that equate to a gif. diff --git a/src/ImageSharp/Formats/Png/PngConstants.cs b/src/ImageSharp/Formats/Png/PngConstants.cs index 48c866f671..62a7b74aba 100644 --- a/src/ImageSharp/Formats/Png/PngConstants.cs +++ b/src/ImageSharp/Formats/Png/PngConstants.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Formats.Png /// /// The default encoding for text metadata. /// - public static readonly Encoding DefaultEncoding = Encoding.GetEncoding("ASCII"); + public static readonly Encoding DefaultEncoding = Encoding.ASCII; /// /// The list of mimetypes that equate to a png. diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs index cc0f8f34dc..f75b09ad04 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// internal sealed partial class IccDataReader { - private static readonly Encoding AsciiEncoding = Encoding.GetEncoding("ASCII"); + private static readonly Encoding AsciiEncoding = Encoding.ASCII; /// /// The data that is read diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs index cfcc66c8e4..f6ce408264 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc internal sealed partial class IccDataWriter : IDisposable { private static readonly bool IsLittleEndian = BitConverter.IsLittleEndian; - private static readonly Encoding AsciiEncoding = Encoding.GetEncoding("ASCII"); + private static readonly Encoding AsciiEncoding = Encoding.ASCII; /// /// The underlying stream where the data is written to diff --git a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs index 9b24bffe85..f4704680e1 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// internal sealed class IccDataTagDataEntry : IccTagDataEntry, IEquatable { - private static readonly Encoding AsciiEncoding = Encoding.GetEncoding("ASCII"); + private static readonly Encoding AsciiEncoding = Encoding.ASCII; /// /// Initializes a new instance of the class. diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs index dc29b19497..2a7d696164 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.Chunks.cs @@ -113,7 +113,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png { // Needs a minimum length of 9 for pHYs chunk. memStream.Write(new byte[] { 0, 0, 0, 9 }, 0, 4); - memStream.Write(Encoding.GetEncoding("ASCII").GetBytes(chunkName), 0, 4); // 4 bytes chunk header + memStream.Write(Encoding.ASCII.GetBytes(chunkName), 0, 4); // 4 bytes chunk header memStream.Write(new byte[] { 0, 0, 0, 0, 0, 0, 0, 0, 0 }, 0, 9); // 9 bytes of chunk data memStream.Write(new byte[] { 0, 0, 0, 0 }, 0, 4); // Junk Crc } From 607d421de759ce6f9f9152c153c78f14e6b824c2 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 09:22:27 -0700 Subject: [PATCH 177/185] Update SixLabors.Drawing minimium netststandard support to v1.3 --- src/ImageSharp.Drawing/ImageSharp.Drawing.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj index 42ef080e53..1cb3f444f0 100644 --- a/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj +++ b/src/ImageSharp.Drawing/ImageSharp.Drawing.csproj @@ -5,8 +5,8 @@ $(packageversion) 0.0.1 SixLabors and contributors - netstandard1.1;netstandard2.0 - 7.2 + netstandard1.3;netstandard2.0 + 7.3 true true SixLabors.ImageSharp.Drawing From 473a7f40ab0daf27bd2da323660e5cff107e76a5 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 09:25:11 -0700 Subject: [PATCH 178/185] Use ASCII Encoding when known to be ASCII --- src/ImageSharp/Formats/Gif/GifConstants.cs | 4 ++-- .../Formats/Jpeg/Components/Decoder/ProfileResolver.cs | 8 ++++---- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifConstants.cs b/src/ImageSharp/Formats/Gif/GifConstants.cs index f8942cc3b7..288c3dfa19 100644 --- a/src/ImageSharp/Formats/Gif/GifConstants.cs +++ b/src/ImageSharp/Formats/Gif/GifConstants.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The ASCII encoded bytes used to identify the GIF file. /// - internal static readonly byte[] MagicNumber = Encoding.UTF8.GetBytes(FileType + FileVersion); + internal static readonly byte[] MagicNumber = Encoding.ASCII.GetBytes(FileType + FileVersion); /// /// The extension block introducer !. @@ -54,7 +54,7 @@ namespace SixLabors.ImageSharp.Formats.Gif /// /// The ASCII encoded application identification bytes. /// - internal static readonly byte[] NetscapeApplicationIdentificationBytes = Encoding.UTF8.GetBytes(NetscapeApplicationIdentification); + internal static readonly byte[] NetscapeApplicationIdentificationBytes = Encoding.ASCII.GetBytes(NetscapeApplicationIdentification); /// /// The Netscape looping application sub block size. diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs index a6d5faaea1..3e7108b151 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs @@ -14,22 +14,22 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder /// /// Describes the EXIF specific markers /// - public static readonly byte[] JFifMarker = Encoding.UTF8.GetBytes("JFIF\0"); + public static readonly byte[] JFifMarker = Encoding.ASCII.GetBytes("JFIF\0"); /// /// Describes the EXIF specific markers /// - public static readonly byte[] IccMarker = Encoding.UTF8.GetBytes("ICC_PROFILE\0"); + public static readonly byte[] IccMarker = Encoding.ASCII.GetBytes("ICC_PROFILE\0"); /// /// Describes the ICC specific markers /// - public static readonly byte[] ExifMarker = Encoding.UTF8.GetBytes("Exif\0\0"); + public static readonly byte[] ExifMarker = Encoding.ASCII.GetBytes("Exif\0\0"); /// /// Describes Adobe specific markers /// - public static readonly byte[] AdobeMarker = Encoding.UTF8.GetBytes("Adobe"); + public static readonly byte[] AdobeMarker = Encoding.ASCII.GetBytes("Adobe"); /// /// Returns a value indicating whether the passed bytes are a match to the profile identifier diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 8401f4e98f..d66ac6c0d2 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1005,7 +1005,7 @@ namespace SixLabors.ImageSharp.Formats.Png if (this.crc.Value != chunk.Crc) { - string chunkTypeName = Encoding.UTF8.GetString(chunkType); + string chunkTypeName = Encoding.ASCII.GetString(chunkType); throw new ImageFormatException($"CRC Error. PNG {chunkTypeName} chunk is corrupt!"); } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs index 35652dd6b5..e4cd06ab1b 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs @@ -24,7 +24,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Png private static PngChunkType GetType(string text) { - return (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(Encoding.UTF8.GetBytes(text)); + return (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(Encoding.ASCII.GetBytes(text)); } } } \ No newline at end of file From 1e38917560d8dfd375559e5ab6eb78e98d636d16 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 09:30:56 -0700 Subject: [PATCH 179/185] Update benchmarks to target netcoreapp2.1 --- tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 36b7d4db4b..a705c9bacb 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -1,11 +1,11 @@  - netcoreapp2.0;net461 + netcoreapp2.1;net461 Exe True SixLabors.ImageSharp.Benchmarks ImageSharp.Benchmarks - 7.2 + 7.3 win7-x64 From 348229b4f2bad76a1d4fa70dbc7579d82f967d15 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 10:10:35 -0700 Subject: [PATCH 180/185] Remove AsciiEncoding field --- .../Profiles/ICC/DataReader/IccDataReader.Primitives.cs | 2 +- .../MetaData/Profiles/ICC/DataReader/IccDataReader.cs | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Primitives.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Primitives.cs index 5be0060f61..bb85a5ca3e 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Primitives.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.Primitives.cs @@ -102,7 +102,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc } Guard.MustBeGreaterThan(length, 0, nameof(length)); - string value = AsciiEncoding.GetString(this.data, this.AddIndex(length), length); + string value = Encoding.ASCII.GetString(this.data, this.AddIndex(length), length); // remove data after (potential) null terminator int pos = value.IndexOf('\0'); diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs index f75b09ad04..91a28fd743 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataReader/IccDataReader.cs @@ -11,8 +11,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// internal sealed partial class IccDataReader { - private static readonly Encoding AsciiEncoding = Encoding.ASCII; - /// /// The data that is read /// From 23982e896f679b24a993c972083af70618c18274 Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 16:01:51 -0700 Subject: [PATCH 181/185] Remove remaining AsciiEncoding fields --- .../Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs | 4 ++-- .../MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs | 2 -- .../Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs | 4 +--- 3 files changed, 3 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs index a58f62519c..404285b500 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.Primitives.cs @@ -178,7 +178,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc return 0; } - byte[] data = AsciiEncoding.GetBytes(value); + byte[] data = Encoding.ASCII.GetBytes(value); this.dataStream.Write(data, 0, data.Length); return data.Length; } @@ -215,7 +215,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc value = value.Substring(0, Math.Min(length - lengthAdjust, value.Length)); - byte[] textData = AsciiEncoding.GetBytes(value); + byte[] textData = Encoding.ASCII.GetBytes(value); int actualLength = Math.Min(length - lengthAdjust, textData.Length); this.dataStream.Write(textData, 0, actualLength); for (int i = 0; i < length - actualLength; i++) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs index f6ce408264..e509f67d72 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs @@ -3,7 +3,6 @@ using System; using System.IO; -using System.Text; namespace SixLabors.ImageSharp.MetaData.Profiles.Icc { @@ -13,7 +12,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc internal sealed partial class IccDataWriter : IDisposable { private static readonly bool IsLittleEndian = BitConverter.IsLittleEndian; - private static readonly Encoding AsciiEncoding = Encoding.ASCII; /// /// The underlying stream where the data is written to diff --git a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs index f4704680e1..4510882904 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/TagDataEntries/IccDataTagDataEntry.cs @@ -12,8 +12,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// internal sealed class IccDataTagDataEntry : IccTagDataEntry, IEquatable { - private static readonly Encoding AsciiEncoding = Encoding.ASCII; - /// /// Initializes a new instance of the class. /// @@ -60,7 +58,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// Gets the decoded as 7bit ASCII. /// If is false, returns null /// - public string AsciiString => this.IsAscii ? AsciiEncoding.GetString(this.Data, 0, this.Data.Length) : null; + public string AsciiString => this.IsAscii ? Encoding.ASCII.GetString(this.Data, 0, this.Data.Length) : null; /// public override bool Equals(IccTagDataEntry other) From 8eebfd1b2aa085ba5c10d2e8f1a97474353f6bcf Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 16:04:19 -0700 Subject: [PATCH 182/185] Update README --- README.md | 20 +------------------- 1 file changed, 1 insertion(+), 19 deletions(-) diff --git a/README.md b/README.md index 66dc0dcf43..3ec925b94b 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Designed to democratize image processing, ImageSharp brings you an incredibly po Compared to `System.Drawing` we have been able to develop something much more flexible, easier to code against, and much, much less prone to memory leaks. Gone are system-wide process-locks; ImageSharp images are thread-safe and fully supported in web environments. -Built against .Net Standard 1.1 ImageSharp can be used in device, cloud, and embedded/IoT scenarios. +Built against .Net Standard 1.3 ImageSharp can be used in device, cloud, and embedded/IoT scenarios. ### Documentation For all SixLabors projects, including ImageSharp: @@ -83,24 +83,6 @@ using (Image image = Image.Load("foo.jpg")) image.Save("bar.jpg"); // Automatic encoder selected based on extension. } ``` -On netstandard 1.1 - 1.2 - -```csharp -using SixLabors.ImageSharp; -using SixLabors.ImageSharp.Processing; - -// Image.Load(Stream stream) is a shortcut for our default type. -// Other pixel formats use Image.Load(Stream stream)) -using (FileStream stream = File.OpenRead("foo.jpg")) -using (FileStream output = File.OpenWrite("bar.jpg")) -using (Image image = Image.Load(stream)) -{ - image.Mutate(x => x - .Resize(image.Width / 2, image.Height / 2) - .Grayscale()); - image.Save(output); -} -``` Setting individual pixel values can be performed as follows: From 4b617ac52d2caed43b00e29f0e7ff935dafa826d Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 16:06:41 -0700 Subject: [PATCH 183/185] Fix .NET casing --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 3ec925b94b..a72074f8f3 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Designed to democratize image processing, ImageSharp brings you an incredibly po Compared to `System.Drawing` we have been able to develop something much more flexible, easier to code against, and much, much less prone to memory leaks. Gone are system-wide process-locks; ImageSharp images are thread-safe and fully supported in web environments. -Built against .Net Standard 1.3 ImageSharp can be used in device, cloud, and embedded/IoT scenarios. +Built against .NET Standard 1.3 ImageSharp can be used in device, cloud, and embedded/IoT scenarios. ### Documentation For all SixLabors projects, including ImageSharp: @@ -115,7 +115,7 @@ If you prefer, you can compile ImageSharp yourself (please do and help!) Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**: - [Visual Studio Code](https://code.visualstudio.com/) with [C# Extension](https://marketplace.visualstudio.com/items?itemName=ms-vscode.csharp) -- [.Net Core](https://www.microsoft.com/net/core#linuxubuntu) +- [.NET Core](https://www.microsoft.com/net/core#linuxubuntu) To clone ImageSharp locally click the "Clone in Windows" button above or run the following git commands. From 97323c9070a70640d7a8e5acb558bca32bde591f Mon Sep 17 00:00:00 2001 From: Jason Nelson Date: Mon, 15 Oct 2018 16:07:07 -0700 Subject: [PATCH 184/185] Use BitConverter.IsLittleEndian directly This allows the JIT can optimize away the unused branch --- .../MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs index e509f67d72..21b7b6421b 100644 --- a/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs +++ b/src/ImageSharp/MetaData/Profiles/ICC/DataWriter/IccDataWriter.cs @@ -11,8 +11,6 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// internal sealed partial class IccDataWriter : IDisposable { - private static readonly bool IsLittleEndian = BitConverter.IsLittleEndian; - /// /// The underlying stream where the data is written to /// @@ -179,7 +177,7 @@ namespace SixLabors.ImageSharp.MetaData.Profiles.Icc /// The number of bytes written private unsafe int WriteBytes(byte* data, int length) { - if (IsLittleEndian) + if (BitConverter.IsLittleEndian) { for (int i = length - 1; i >= 0; i--) { From b697c6dcb7b709bcd1d265c0626b46ad063a5737 Mon Sep 17 00:00:00 2001 From: j0rn Date: Tue, 16 Oct 2018 10:23:03 +0200 Subject: [PATCH 185/185] Using FormattableString.Invariant. --- src/ImageSharp/ColorSpaces/CieLab.cs | 3 +-- src/ImageSharp/ColorSpaces/CieLch.cs | 3 +-- src/ImageSharp/ColorSpaces/CieLchuv.cs | 3 +-- src/ImageSharp/ColorSpaces/CieLuv.cs | 3 +-- .../ColorSpaces/CieXyChromaticityCoordinates.cs | 3 +-- src/ImageSharp/ColorSpaces/CieXyy.cs | 3 +-- src/ImageSharp/ColorSpaces/CieXyz.cs | 3 +-- src/ImageSharp/ColorSpaces/Cmyk.cs | 3 +-- src/ImageSharp/ColorSpaces/Hsl.cs | 3 +-- src/ImageSharp/ColorSpaces/Hsv.cs | 3 +-- src/ImageSharp/ColorSpaces/HunterLab.cs | 3 +-- src/ImageSharp/ColorSpaces/LinearRgb.cs | 3 +-- src/ImageSharp/ColorSpaces/Lms.cs | 3 +-- src/ImageSharp/ColorSpaces/Rgb.cs | 3 +-- src/ImageSharp/ColorSpaces/YCbCr.cs | 3 +-- src/ImageSharp/Common/Helpers/FloatToStringUtil.cs | 11 ----------- 16 files changed, 15 insertions(+), 41 deletions(-) delete mode 100644 src/ImageSharp/Common/Helpers/FloatToStringUtil.cs diff --git a/src/ImageSharp/ColorSpaces/CieLab.cs b/src/ImageSharp/ColorSpaces/CieLab.cs index d7af041204..ea6df86e27 100644 --- a/src/ImageSharp/ColorSpaces/CieLab.cs +++ b/src/ImageSharp/ColorSpaces/CieLab.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -128,7 +127,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLab({FloatToString(this.L, this.A, this.B)})"; + public override string ToString() => FormattableString.Invariant($"CieLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); /// public override bool Equals(object obj) => obj is CieLab other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieLch.cs b/src/ImageSharp/ColorSpaces/CieLch.cs index b0192b214f..f1a7425e9e 100644 --- a/src/ImageSharp/ColorSpaces/CieLch.cs +++ b/src/ImageSharp/ColorSpaces/CieLch.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -130,7 +129,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLch({FloatToString(this.L, this.C, this.H)})"; + public override string ToString() => FormattableString.Invariant($"CieLch({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/ColorSpaces/CieLchuv.cs b/src/ImageSharp/ColorSpaces/CieLchuv.cs index 3e0d654dd7..256b5dc0fd 100644 --- a/src/ImageSharp/ColorSpaces/CieLchuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLchuv.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -129,7 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLchuv({FloatToString(this.L, this.C, this.H)})"; + public override string ToString() => FormattableString.Invariant($"CieLchuv({this.L:#0.##}, {this.C:#0.##}, {this.H:#0.##})"); /// public override bool Equals(object obj) => obj is CieLchuv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieLuv.cs b/src/ImageSharp/ColorSpaces/CieLuv.cs index e0c17224da..8fe073d6bf 100644 --- a/src/ImageSharp/ColorSpaces/CieLuv.cs +++ b/src/ImageSharp/ColorSpaces/CieLuv.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -129,7 +128,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieLuv({FloatToString(this.L, this.U, this.V)})"; + public override string ToString() => FormattableString.Invariant($"CieLuv({this.L:#0.##}, {this.U:#0.##}, {this.V:#0.##})"); /// public override bool Equals(object obj) => obj is CieLuv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs index e29411f670..f625bb7616 100644 --- a/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs +++ b/src/ImageSharp/ColorSpaces/CieXyChromaticityCoordinates.cs @@ -3,7 +3,6 @@ using System; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; // ReSharper disable CompareOfFloatsByEqualityOperator namespace SixLabors.ImageSharp.ColorSpaces @@ -68,7 +67,7 @@ namespace SixLabors.ImageSharp.ColorSpaces public override int GetHashCode() => HashHelpers.Combine(this.X.GetHashCode(), this.Y.GetHashCode()); /// - public override string ToString() => $"CieXyChromaticityCoordinates({FloatToString(this.X, this.Y)})"; + public override string ToString() => FormattableString.Invariant($"CieXyChromaticityCoordinates({this.X:#0.##}, {this.Y:#0.##})"); /// public override bool Equals(object obj) => obj is CieXyChromaticityCoordinates other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyy.cs b/src/ImageSharp/ColorSpaces/CieXyy.cs index a036e89c3e..7137360e94 100644 --- a/src/ImageSharp/ColorSpaces/CieXyy.cs +++ b/src/ImageSharp/ColorSpaces/CieXyy.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -92,7 +91,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieXyy({FloatToString(this.X, this.Y, this.Yl)})"; + public override string ToString() => FormattableString.Invariant($"CieXyy({this.X:#0.##}, {this.Y:#0.##}, {this.Yl:#0.##})"); /// public override bool Equals(object obj) => obj is CieXyy other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/CieXyz.cs b/src/ImageSharp/ColorSpaces/CieXyz.cs index f6d6e285e9..c0ed356601 100644 --- a/src/ImageSharp/ColorSpaces/CieXyz.cs +++ b/src/ImageSharp/ColorSpaces/CieXyz.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -95,7 +94,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"CieXyz({FloatToString(this.X, this.Y, this.Z)})"; + public override string ToString() => FormattableString.Invariant($"CieXyz({this.X:#0.##}, {this.Y:#0.##}, {this.Z:#0.##})"); /// public override bool Equals(object obj) => obj is CieXyz other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Cmyk.cs b/src/ImageSharp/ColorSpaces/Cmyk.cs index e351642de5..634667c0c6 100644 --- a/src/ImageSharp/ColorSpaces/Cmyk.cs +++ b/src/ImageSharp/ColorSpaces/Cmyk.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -100,7 +99,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Cmyk({FloatToString(this.C, this.M, this.Y, this.K)})"; + public override string ToString() => FormattableString.Invariant($"Cmyk({this.C:#0.##}, {this.M:#0.##}, {this.Y:#0.##}, {this.K:#0.##})"); /// public override bool Equals(object obj) => obj is Cmyk other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Hsl.cs b/src/ImageSharp/ColorSpaces/Hsl.cs index 5684d81840..f6e531df35 100644 --- a/src/ImageSharp/ColorSpaces/Hsl.cs +++ b/src/ImageSharp/ColorSpaces/Hsl.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -93,7 +92,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Hsl({FloatToString(this.H, this.S, this.L)})"; + public override string ToString() => FormattableString.Invariant($"Hsl({this.H:#0.##}, {this.S:#0.##}, {this.L:#0.##})"); /// public override bool Equals(object obj) => obj is Hsl other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Hsv.cs b/src/ImageSharp/ColorSpaces/Hsv.cs index 9d40a6d3fd..631f03d09f 100644 --- a/src/ImageSharp/ColorSpaces/Hsv.cs +++ b/src/ImageSharp/ColorSpaces/Hsv.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -91,7 +90,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Hsv({FloatToString(this.H, this.S, this.V)})"; + public override string ToString() => FormattableString.Invariant($"Hsv({this.H:#0.##}, {this.S:#0.##}, {this.V:#0.##})"); /// public override bool Equals(object obj) => obj is Hsv other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/HunterLab.cs b/src/ImageSharp/ColorSpaces/HunterLab.cs index 3e336ca681..f4fa29d314 100644 --- a/src/ImageSharp/ColorSpaces/HunterLab.cs +++ b/src/ImageSharp/ColorSpaces/HunterLab.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -127,7 +126,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"HunterLab({FloatToString(this.L, this.A, this.B)})"; + public override string ToString() => FormattableString.Invariant($"HunterLab({this.L:#0.##}, {this.A:#0.##}, {this.B:#0.##})"); /// public override bool Equals(object obj) => obj is HunterLab other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/LinearRgb.cs b/src/ImageSharp/ColorSpaces/LinearRgb.cs index c376a4d1d4..ec6d18be2b 100644 --- a/src/ImageSharp/ColorSpaces/LinearRgb.cs +++ b/src/ImageSharp/ColorSpaces/LinearRgb.cs @@ -5,7 +5,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -135,7 +134,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"LinearRgb({FloatToString(this.R, this.G, this.B)})"; + public override string ToString() => FormattableString.Invariant($"LinearRgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"); /// public override bool Equals(object obj) => obj is LinearRgb other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Lms.cs b/src/ImageSharp/ColorSpaces/Lms.cs index 823d1c1e1f..0a8b7aa7b9 100644 --- a/src/ImageSharp/ColorSpaces/Lms.cs +++ b/src/ImageSharp/ColorSpaces/Lms.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -96,7 +95,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Lms({FloatToString(this.L, this.M, this.S)})"; + public override string ToString() => FormattableString.Invariant($"Lms({this.L:#0.##}, {this.M:#0.##}, {this.S:#0.##})"); /// public override bool Equals(object obj) => obj is Lms other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/Rgb.cs b/src/ImageSharp/ColorSpaces/Rgb.cs index 5ccabdfaab..97fafbaf37 100644 --- a/src/ImageSharp/ColorSpaces/Rgb.cs +++ b/src/ImageSharp/ColorSpaces/Rgb.cs @@ -6,7 +6,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.ColorSpaces.Conversion.Implementation; using SixLabors.ImageSharp.PixelFormats; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -156,7 +155,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"Rgb({FloatToString(this.R, this.G, this.B)})"; + public override string ToString() => FormattableString.Invariant($"Rgb({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##})"); /// public override bool Equals(object obj) => obj is Rgb other && this.Equals(other); diff --git a/src/ImageSharp/ColorSpaces/YCbCr.cs b/src/ImageSharp/ColorSpaces/YCbCr.cs index bbf3f9db22..6aa191c2de 100644 --- a/src/ImageSharp/ColorSpaces/YCbCr.cs +++ b/src/ImageSharp/ColorSpaces/YCbCr.cs @@ -4,7 +4,6 @@ using System; using System.Numerics; using System.Runtime.CompilerServices; -using static SixLabors.ImageSharp.Common.Helpers.FloatToStringUtil; namespace SixLabors.ImageSharp.ColorSpaces { @@ -92,7 +91,7 @@ namespace SixLabors.ImageSharp.ColorSpaces } /// - public override string ToString() => $"YCbCr({FloatToString(this.Y, this.Cb, this.Cr)})"; + public override string ToString() => FormattableString.Invariant($"YCbCr({this.Y}, {this.Cb}, {this.Cr})"); /// public override bool Equals(object obj) => obj is YCbCr other && this.Equals(other); diff --git a/src/ImageSharp/Common/Helpers/FloatToStringUtil.cs b/src/ImageSharp/Common/Helpers/FloatToStringUtil.cs deleted file mode 100644 index fbb3f8750c..0000000000 --- a/src/ImageSharp/Common/Helpers/FloatToStringUtil.cs +++ /dev/null @@ -1,11 +0,0 @@ -using System.Globalization; -using System.Linq; - -namespace SixLabors.ImageSharp.Common.Helpers -{ - internal static class FloatToStringUtil - { - internal static string FloatToString(params float[] values) - => string.Join(", ", values.Select(v => v.ToString("#0.##", CultureInfo.InvariantCulture)).ToArray()); - } -}